Cflp

Laborator

Facultatea de Automatica si Calculatoare 

Departamentul de Calculatoare

 

Home Lucrarea 1 Lucrarea 2 Lucrarea 3 Lucrarea 4 Lucrarea 5 Proiect
  Lucrarea 6 Lucrarea 7 Lucrarea 8 Lucrarea 9 Lucrarea 10  

 

      Lucrarea 5
 

 

 

Subiecte

 

LAMBDA defineşte proceduri anonime

 

Să presupunem că avem o listă de numere:

numbers

(4 6 3 8 9 7)

şi div3 este o procedură care verifică dacă un număr este divizibil cu trei.

 

(defun div3 (x)

(zerop (rem x 3)))

 

Folosind mapcar cu procedura div3 putem verifica elementele din listă care sunt divizibile cu trei:

 

(mapcar 'div3 numbers)

(nil t t nil t nil)

 

Dacă funcţia div3 nu o mai folosim īn altă parte, putem să o definit chiar īn locul īn care apare (mapcar poate primi nu numai numele unei funcţii ci chiar definiţia ei):

(mapcar (defun div3 (x) (zerop (rem x 3)))

numbers)

(nil t t nil t nil)

 

De fapt mapcar primeşte tot numele unei proceduri, pentru că defun după ce defineşte procedura returnează numele ei (vezi lucrarea 2).

Observăm că numele procedurii div3 nu mai este util dacă procedura apare doar īn acest loc. Ar fi util, pentru a evita proliferarea numelor inutile, ca procedura care verifică dacă un număr este divizibil cu trei să nu aibă nume (să fie anonimă). Acest lucru īl specificăm primtr-o primitivă asemănătoare cu defun, numită din motive istorice lambda. Deci pentru a folosi o definiţie locală anonimă scriem:

(mapcar '(lambda (x) (zerop (rem x 3)))

numbers)

(nil t t nil t nil)

 

Primitiva lambda seamănă foarte mult cu defun, doar că nu dă nume procedurii definite, putānd fi folosită astfel doar īn definiţii locale.

Observaţi că primitiva lambda poate să apară practic oriunde apare numele unei funcţii. Īn particular poate să apară pe prima poziţie a unei forme care va fi evaluată. Următoarele expresii sunt echivalente, presupunānd definit div3:

(div3 6)

((lambda (x) (zerop (rem x 3))) 6)

Urmăriţi următorul exemplu īn care definim o procedură care numără cāte elemente dintr-o listă sunt divizibile cu trei:

 

(defun count-div3 (l)

(apply '+ (mapcar '(lambda (x)

(cond ((zerop (rem x 3)) 1)

(t 0)))

l)))

(count-div3 numbers)

3

 

Predicatul REMOVE-IF-NOT

 

Predicatul remove-if-not este asemănător cu mapcar dar păstrează īn rezultatul final doar elementele pentru care un anumit predicat este adevărat.

(remove-if-not 'div3 numbers)

(6 3 9)

 

Şi aici putem folosi lambda:

(remove-if-not '(lambda (x) (zerop (rem x 3)))

numbers)

(6 3 9)

 

Lambda interfaţează proceduri la liste de argumente

Considerăm o listă generalizată īn care dorim să numărăm elementele divizibile cu un număr dat:

 

(defun count-deep-div (n l)

(cond ((atom l) (cond ((zerop (rem l n)) 1)

(t 0)))

(t (apply '+ (mapcar '(lambda (e) (count-deep-div n e))

l)))))

Nu puteam aplica recursiv direct (mapcar 'count-deep-div3 l) pentru că procedura count-deep-div3 are nevoie de doi parametrii iar mapcar īi furnizează doar cāte unul. Aici lambda reailzează interfaţarea dorită a procedurii.

 

Probleme

 

1. Realizaţi, folosind mapcar şi lambda, o procedură presentp care determină dacă un atom există īntr-o listă generalizată.