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