Documente Academic
Documente Profesional
Documente Cultură
by Mihai Maruseac
Am arătat ı̂n laboratorul trecut cum putem implementa unele structuri de date ca
funct, ii. Vom insista azi put, in asupra acestui lucru s, i vom trece apoi la a studia
modul de transmitere a parametrilor ı̂n Scheme.
Lambda0
Ne amintim din laboratorul trecut ca puteam reprezenta tipuri de date s, i structuri
ca funct, ii ı̂n formă curry cu mai multe argumente:
(define and
(lambda (x)
(lambda (y) ((x y) false))))
(define or
(lambda (x)
(lambda (y) ((x true) y))))
Ne amintim că true returna primul argument iar false pe al doilea s, i că ne-am
folosit de acest lucru pentru a genera codul pentru celelalte operat, ii.
Pornind de la aceste definit, ii, vom extinde lumea tipurilor de date cu ı̂ncă trei
structuri:
I tipul pereche - Pair. Avem nevoie de funct, ii pentru a accesa primul s, i al
doilea element:
(define pair
(lambda (x)
(lambda (y)
(lambda (z)
((z x) y)))))
(define fst
(lambda (p)
(p true)))
(define snd
(lambda (p)
(p false)))
I tipul listă - List. T, inând cont că o listă este de fapt o pereche cu cons s, i
car implementarea este us, oară:
(define conss pair)
(define carr fst)
(define cdrr snd)
(define nil
(lambda (x)
true))
(define null
(lambda (l)
(l (lambda (x) (lambda (y) false)))))
Funct, ia nil returnează lista vidă iar null este predicatul pentru a testa dacă
o listă e vidă.
I tipul număr natural - Number. Ne bazăm pe tipul listă s, i pe reprezentarea
mult, imii numerelor naturale ı̂n baza 1 (aritmetica lui Peano)
(define n0 nil)
(define succ (lambda (n) ((conss nil) n)))
(define pred cdrr)
(define zero nulll)
Evaluare aplicativă
Evaluarea cea mai des ı̂ntâlnită este cea aplicativă. O ı̂ntânlnim ı̂n toate limbajele
imperative s, i ı̂n Scheme (s, i ı̂n alte limbaje). Deoarece parametrii se evaluează ı̂na-
2
intea aplicării funct, iei asupra lor, orice funct, ie va vedea doar valorile parametrilor.
Spunem că transferul lor se face prin valoare.
Des, i această metodă are avantajul economisirii spat, iului ocupat pe stivă ı̂n mo-
menul apelării unei funct, ii, are s, i anumite dezavantaje. Cel mai important este
faptul că nu putem lucra cu structuri de date infinite, de exemplu, fluxul tuturor
numerelor naturale. Des, i are o reprezentare finită, această structură infinită nu
poate fi reprezentată astfel.
Evaluarea lenes, ă
Putem obt, ine o asemenea reprezentare dacă argumentele nu ar fi evaluate la apel
ci ı̂n momentul ı̂n care sunt necesare valorile lor. Este metoda de evaluare din
Haskell.
Putem avea evaluare lenes, ă s, i ı̂n Scheme prin următoarele metode:
I funct, ii cu 0 parametri
I promisiuni
Funct, ii cu 0 parametri
Deoarece funct, iile sunt valori ı̂n programarea funct, ională, le putem folosi oriunde
este nevoie de un parametru cu evaluare ı̂ntârziată. Tot ce trebuie să facem este
să-l ı̂nlocuim printr-o funct, ie cu 0 argumente, la evaluarea căreia se va returna
valoarea argumentului. Obt, inem o ı̂nchidere funct, ională ce ne va da argumentul
cerut doar când avem nevoie de el.
Fie următorul exemplu:
(define sum
(lambda (x y)
(lambda ()
(+ x y))))
(sum 1 2) ; va ı
^ntoarce #<procedure>, e funct, ie
3
Promisiuni
Folosirea metodei anterioare presupune definirea de noi funct, ii pentru orice argu-
ment a cărui evaluare vrem s-o ı̂ntârziem. Uneori, acest lucru este greu de realizat.
Din fericire, Scheme vine cu un mod propriu de a trata acest aspect: promisiu-
nile.
O promisiune este o garant, ie că se va calcula o valoare dar numai atunci când
ea va fi necesară s, i se va fort, a promisiunea.
De exemplu, dacă avem definit, ia convent, ională pentru suma a două numere:
(define sum
(lambda (x y)
(+ x y)))
putem obt, ine o promisiune prin ı̂ntârzierea evaluării funct, iei utilizând delay:
Fluxuri
Cea mai importantă utilizare a evaluării lenes, e o reprezintă posibilitatea definirii
de fluxuri. De exemplu, s, irul numerelor naturale reprezintă un flux.
Putem reprezenta un flux ca o pereche (reprezentare finită!) unde:
I primul element reprezintă valoarea curentă din flux
I al doilea element reprezintă o funct, ie generator
La apelarea funct, iei generator se va ı̂ntoarce următoarea pereche din flux.
Fluxul (1,1,1...) poate fi definit astfel:
I utilizând funct, ii fără argumente
(define ones
(lambda ()
(cons 1 (lambda () (ones)))))
(define take
(lambda (n stream)
(if (= n 0) ’()
(cons (car stream)
(take (- n 1)
((cdr stream))
)))))
4
Observat, i faptul că s-au folosit două rânduri de paranteze pe ultima linie
utilă din take - ((cdr stream)) - pentru a se obt, ine următoarea pereche
prin evaluarea funct, iei cu 0 parametri.
I utilizând promisiuni
Exercit, ii
1. Definit, i numerele naturale reprezentând numărul n ca o listă cu n elemente
1 (folosit, i lista existentă ı̂n Scheme). Definit, i adunarea, scăderea, ı̂nmult, irea
s, i ı̂mmpărt, irea cu rezultate numere naturale.
6. *** Utilizând un flux de numere naturale definit, i operat, iile pe numere mari:
adunare, scădere, ı̂nmult, ire.