This is an old revision of the document!
===== Laborator 9 - Întârzierea evaluării ===== =====Moduri de evaluare a unei expresii: ===== * **evaluare aplicativa** - argumentele funcțiilor sunt evaluate înaintea aplicării funcției asupra lor. * **evaluare lenesa** - întârzie evaluarea parametrilor până în momentul când aceasta este folosită efectiv. * **promisiuni** ====Evaluare aplicativă vs. evaluare leneșă==== Fie urmatoarea expresie, scrisă în calcul Lambda: <code>(λx.λy.(x + y) 1 2)</code> Evident, in urma aplicării funcției de mai sus, expresia se va evalua la 3. Sa observam, insa, cazul in care parametrii functiei reprezinta aplicatii de functii: <code>(λx.λy.(x + y) 1 (λz.(z + 2) 3))</code> Desigur, evaluarea expresiei ''(λz.(z + 2) 3)'' va genera valoarea ''5'', de unde deducem ca rezultatul final al expresiei va fi ''6'' ( adunarea lui 1 cu rezultatul anterior ). În cadrul acestui raționament, am presupus că parametrii sunt evaluați înaintea aplicării funcției asupra acestora. Vom vedea, în cele ce urmează, că evaluarea se poate realiza și in alt mod. ====Evaluare aplicativă==== Evaluarea aplicativă (eager evaluation) este cea în care fiecare expresie este evaluată imediat. În exemplul de mai sus, evaluarea aplicativă va decurge astfel: <code>(λx.λy.(x + y) 1 (λz.(z + 2) 3)) (λx.λy.(x + y) 1 5) 6</code> ====Evaluare leneșă==== Spre deosebire de evaluarea aplicativă, evaluarea leneșă va întarzia evaluarea unei expresii, până când aceasta este folosită efectiv. Exemplu: <code>(λx.λy.(x + y) 1 (λz.(z + 2) 3)) (1 + (λz.(z + 2) 3)) (1 + 5) 6</code> ====Evaluarea in Racket==== Evaluarea in Racket este by default aplicativa. codul ''(+ 1 (+ 2 3))'' pentru a se evalua si a intoarce 6, urmeaza etapele: * ''(+ 2 3)'' se evalueaza intai, al doilea parmetru al funcției ''+'' si produce 5 * ''(+ 1 5)'' se evalueaza si produce 6 Totuși, putem intarzia evaluarea expresiilor prin inchideri nulare <code>(define suma (lambda (a b) (+ a b))) (define suma_intarziata (lambda (a b) (lambda () (+ a b) )))</code> * ''(suma_intarziata 2 3)'' intoarce un ''#procedure'' (functie) care isi salveaza contextul ( inchidere functionala ) * ''(''''(suma_intarziata 2 3)'''')'' intoarce rezultatul ====Aplicatii:==== 1. Definiți un stream de numere 1 'ones_stream' folosind evaluarea lenesa din scheme care apeland * ''(ones_stream)'' => ''(1 . #procedure)'' unde dacă vom apela ''(#procedure)'', vom obtine: * ''(1 . #procedure)'' din nou. 2. Creati o funcție take care să funcționeze ca cea din haskell (take 5 [1,1..] va intoarce [1,1,1,1,1] in haskell) * ''(take 5 ones_stream)'' => ''(1 1 1 1 1)'' 3. Creati un stream de numere naturale care va fi reprezentat astfel: * ''(0 . #procedure)'', unde dacă vom apela procedure vom obtine * ''(1 . #procedure)'', unde dacă iar apelam procedure-ul nou obtinut, obtinem * ''(2 . #procedure)'' etc. * HINT: veți avea nevoie de o funcție ajutătoare * Testați: ''(take 5 naturals_stream)'' => ''(0 1 2 3 4)'' 4. Definiți o funcție care sa adune două stream-uri: * ''(take 5 (sum_stream naturals_stream ones_stream))'' => ''(1 2 3 4 5)'' 5. Creați un stream de numere pare: * Testati: ''(take 5 even_stream)'' => ''(0 2 4 6 8)'' 6. Creați șirul numerelor fibonacci: * ''(take 5 fibo_stream)'' => ''(0 1 1 2 3)'' * Observam ca fibonacci e definit prin adunarea stream-urilor anterioare. <code> Fibo = t0 t1 t2 t3 ... t(k-2) ... + (tail Fibo) = t1 t2 t3 t4 ... t(k-1) ... ___________________________________________ Fibo = t0 t1 t2 t3 t4 t5 ... tk ... </code> * Observam că, adunand elemente din sirurile (fluxurile) Fibo și (tail Fibo), obtinem sirul t2 t3 t4 .. tk . Dacă adăugam primele două elemente, t0 si t1 la inceput, obținem exact Fibo.