|
Subiecte
|
|
Parametri opţionali
La definirea unei funcţii putem specifica faptul că un parametru
este opţional:
OPTIONAL |
(defun putere (x &optional y)
(cond
((not y) x) ; y == 1
(t
(expt x y)))) |
Funcţia de mai sus dacă primeşte un singur argument, consideră
că cel de al doilea este 1. Putere dă şi o valoare implicită parametrului
opţional:
OPTIONAL |
(defun putere (x &optional (y 1))
(expt
x y)) |
Pot exista oric�ţi parametri opţionali. Poate exista şi un singur
parametru semnalat de &rest, a cărui valoare devine o listă cu toate
argumentele �n plus faţă de cele specificate la definirea funcţiei.
REST |
(defun my-or (&rest r)
(cond ((null r) nil)
((car r))
(t (apply
'my-or (cdr r))))) |
Macrouri
Macrourile sunt definite ca şi funcţiile dar ele nu �şi evaluează
niciodată argumentele.
DEFMACRO |
Urmăriţi cu atenţie exemplul următor:
(defmacro demo (par)
(print par))
(setq this 'value-of-this)
(demo this)
this
value-of-this |
La apelul macroului nu se �ncearcă evaluarea lui this, deci chiar
this devine valoarea lui par şi se afişează this. La returnare �nsă
this se evaluează.
OUR-IF |
�n exeplul următor se implementează un macro our-if.
(defmacro our-if (test success failure)
(subst test 'test
(subst success 'success
(subst failure 'failure
'(cond (test success)
(t failure))))))
Parametrul failure poate fi declarat opţional.
|
Backquote
Mecanismul backquote permite uşor generarea de expresii a căror
mare parte este fixată şi doar c�teva variabile trebuie �nlocuite.
Caracterul backquote (`) acţionează asemănator
cu quote (') cu observaţia că orice virgule
ce apar �n interior au efect de unquoting. pentru expresia
următoare.
Backquote |
(setq variable 'example)
example
`(this is an ,variable)
(this is an example)
|
OUR-IF 2 |
Folosind mecanismul backquote our-if
devine:
(defmacro our-if (test success &optional failure)
`(cond (,test ,success) (t ,failure)))
|
Problema 1 |
Definiţi un macro define care defineşte o funcţie
dar av�nd sintaxa:
(define (<nume functie> <param 1> ...
<param n>)
<corp>)
|
Problema 2 |
Definiţi un macro dotimes cu sintaxa:
(dotimes (<var> <count> <rezultat>)
<corp>)
Prima dată se evaluează <count>
care trebuie să dea un �ntreg. Apoi <var>
este succesiv legata la �ntregi de la 0
la valoarea lui <count> minus
1. Corpul este evaluat de fiecare dată
iar <rezultat> este returnat la
sf�rşit.
Observaţie: căutaţi o formă folosind do
care este echivalentă şi apoi scrieţi macroul dotimes.
|
CONS
CONS construieşte noi liste folosind celule libere.
LISP pastrează o listă de celule libere din care se consumă
la cerere celule. (La epuizarea celulelor libere se execută un
algoritm garbage collection). CONS ia prima celulă din
lista de celule libere şi �i modifică pointerul de legatură
cu urmatoarea celulă.
CONS |
Presupunem că avem:
(setq exemplu '(b c))
Evaluarea lui
(cons 'a exemplu)
va scoate din câmpul listei de celule libere
o celulă al cărui conţinut va fi a
iar pointerul către celula următoare va fi la adresa celulei
al cărei conţinut este b din lista
(b c). Se va retuna adresa celulei ce
conţine pe a (câmpul noii liste).
|
APPEND
APPEND construieşte o nouă listă prin
copiere.
APPEND |
Să presupunem că evaluăm expresiile:
(setq abc '(a b c))
(setq xyz '(x y z))
Avem acum două liste, (a b c) şi (x y z) al
căror adresă de �nceput este memorată de abc respectiv xyz.
Ce se �nt�mplă la evaluarea expresiei
(setq abcxyz (append abc xyz)) ?
Ceea ce am fi tentaţi să credem, dar nu se �nt�mplă, este următorul
lucru: lista (a b c) este legată de lista (x y z) prin faptul
că pointerul ce indică celula următoare a lui c (care iniţial
este nil) va pointa �nceputul listei (x y z) (deci valoarea lui
xyz), iar ceea ce retunează append este valoarea lui abc. Dacă
lucrurile descrise mai sus s-ar �nt�mpla atunci după evaluarea
expresiei listele pointate de abc şi abcxyz vor fi identice,
lucru care nu se �nt�mplă. Felul �n care append lucrează este
urmatorul: creează o nouă listă copiind lista (a b c) (folosind
desigur celule libere), iar listei nou creeate �i modifică ultimul
pointer leg�ndu-l la începutul liste (x y z), după care reurnează
�nceputul noii liste. Astfel primele trei celule din lista (a
b c x y z)sunt copii ale celulelor din lista (a b c)pe c�nd
ultimele trei celule sunt exact celulele din lista (x y z).
|
Funcţii cu efect distructiv
NCONC, RPLACA, RPLACD şi DELETE
Aceste predicate alterează conţinutul celulelor de memorie şi trebuie
folosite cu mare atenţie.
NCONC face exact ceea ce am fost tentaţi să credem că face APPEND.
Concatenează două liste modific�nd ultima celulă a primei liste şi
nu prin copiere.
NCONC |
(setq abcxyz (nconc abc xyz))
(a b c x y z)
abc
(a b c x y z)
xyz
(x y z)
|
NCONC, la fel ca şi APPEND, poate lua mai multe argumente alter�nd
sf�rşitul fiecărei liste �n afară de ultima.
RPLACA primeşte două argumente din care primul trebuie să fie o listă.
Alterează această lista �nlocuind conţinutul primei celule cu al
doilea argument. Numele provine de la RePLAce CAr.
RPLACD este complementar, alterează restul listei (pointerul către
celula următoare al primei celule).
DELETE elimină apariţiile primului argument �n primul nivel al celui
de al doilea argument, dar fizic nu alterează lista iniţială.
DELETE |
(delete 'a '(a b b a b))
(b b b)
|
EQUAL diferă de EQL
Pentru EQL două liste sunt identice doar dacă sunt reprezentate
�n aceleaşi celule de memorie. Copiile nu sunt considerate identice
de către EQL , dar sunt considerate egale de către EQUAL.
Problema 3 |
REVERSE inversează o lista prin copiere. Scrieţi
o funcţia REV care inversează fizic celulele dintr-o listă. Funcţia trebuie să returneze o listă formată din acelaşi celule - construirea şi/sau returnarea unei noi liste nu este permisă!
(setq l ' (a b c d))
((a b c d)
(rev l)
(d c b a)
l
(d c b a)
|
Probleme
Problema 1. Define
Problema 2. Dotimes
Problema 3. Reverse destructiv
|