|
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
|