Table of Contents

Întârzierea evaluării

Moduri de evaluare a unei expresii:

Evaluare aplicativă vs. evaluare normala

Fie urmatoarea expresie, scrisă într-o varianta relaxata a Calculului Lambda (in care valori numerice si operatii pe acestea sunt permise, iar functiile sunt in forma uncurry):

(λx.λy.(x + y) 1 2)

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:

(λx.λy.(x + y) 1 (λz.(z + 2) 3))

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:

(λx.λy.(x + y) 1 (λz.(z + 2) 3))
(λx.λy.(x + y) 1 5)
6

Evaluare normală

Spre deosebire de evaluarea aplicativă, evaluarea normală va întarzia evaluarea unei expresii, până când aceasta este folosită efectiv. Exemplu:

(λx.λy.(x + y) 1 (λz.(z + 2) 3))
(1 + (λz.(z + 2) 3))
(1 + 5)
6

Evaluarea in Racket

Evaluarea in Racket este by default aplicativă. Codul (+ 1 (+ 2 3)) pentru a se evalua si a intoarce 6, urmează etapele:

Totuși, putem intarzia evaluarea expresiilor prin inchideri nulare

(define suma
  (lambda (a b)
    (+ a b)))

(define suma_intarziata
  (lambda (a b)
    (lambda () (+ a b)
    )))

Aplicatii:

Siruri in Scheme

  1. Definiți un stream de numere 1 'ones_stream' folosind evaluarea normala din Scheme
  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)
    • pentru acest task, implementati o functie zipWith care sa opereze pe stream-uri
  5. Creați un stream de numere pare:
    • Testati: (take 5 even_stream)(0 2 4 6 8)
    • pentru acest task, implementati o functie map care sa opereze pe stream-uri
  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.
              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 ...  

Siruri in Haskell

  1. Construiti sirul numerelor naturale
  2. Construiti sirul numerelor pare
  3. Construiti sirul numerelor lui Fibonacci

Aproximatii (in Haskell)

  1. definiti o functie build :: (a → a) → a → [a] care primeste o functie 'generator' (pe care o numim g in continuare), o valoare initiala (a0), si generaza lista: [a0, g a0, g (g a0), g (g (g a0)), …
  2. definiti o functie select care primeste o toleranta e, o lista, si intoarce valoarea an care satisface proprietatea: |an - a{n+1}| < e
  3. Aproximatie pentru sqrt(k):
    • Scrieti o functie care calculeaza sqrt(k) cu toleranta 0.01, exploatand faptul ca sirul: an = 1/2(a{n-1} + k/a{n-1}) converge catre sqrt(k) cand n tine de la infinit.
  4. Aproximatie pentru derivata unei functii f intr-un punct a
    • Scrieti o functie care genereaza lista: [h0, h0/2, h0/4, h0/8, …]
    • Scrieti o functie care calculeaza lista aproximarilor lui f'(a), calculate astfel: f'(a)=f(a+h)-f(a)/h
    • Scrieti o functie care calculeaza derivata in a a unei functii f, cu toleranta 0.01
  5. Aproximatie pentru integrala unei functii pe intervalul [a,b]
    • Scrieti o functie care aproximeaza valoarea integralei unei functii f intre a si b, cu toleranta 0.01. Strategia de imbunatatire a unei aproximari consta in spargerea intervalului [a,b] in doua sub-intervale de dimensiune egala [a,m] si [m,b], calculul integralei pe fiecare, si adunarea rezultatului.

Solutii

Solutii (inclusiv pentru laboratorul 9)