Documente Academic
Documente Profesional
Documente Cultură
n limbajele de programare funcional iterarea se face prin metoda recursivitaii. Funciile recursive se apeleaza permind efectuarea unui calcul n mod repetat. Limbajele funcionale pot fi clasificate dup utilizarea evalurii stricte sau nonstricte, concepte ce se refer la modul n care sunt prelucrate argumentele unei funcii la evaluarea expresiei. Pe scurt, evaluarea strict evalueaz mereu complet argumentele funciilor nainte de invocarea funciei. Evaluarea non-strict poate proceda altfel. De exemplu, se consider urmtoarele dou funcii f i g: f(x) := x^2 + x + 1 g(x, y) := x + y n evaluare strict, va trebui s se evalueze argumentele funciilor nti, de exemplu: f(g(1, 4)) = f(1 + 4) = f(5) = 5^2 + 5 + 1 = 31
Evaluarea non-strict nu trebuie s evalueze complet argumentele; n particular, poate trimite funciei argumentele neevaluate, urmnd ca acestea s fie evaluate mai trziu. De exemplu, o strategie non-strict de evaluare (apel dup nume) ar putea funciona astfel: f(g(1, 4)) = g(1, 4)^2 + g(1, 4) + 1 = (1 + 4)^2 + (1 + 4) + 1 = 5^2 + 5 + 1 = 31 O proprietate-cheie a evalurii stricte este c atunci cnd evaluarea unui argument nu se mai termin, ntreaga expresie nu se termin. La evaluarea non-strict, nu se ntmpl aa n mod necesar, deoarece argumentele ar putea s nu mai fie evaluate deloc.
Parametrii sunt de regul trimii ca uniti atomice simple, i nu ca expresii complexe. (De exemplu, ntregul 5 poate fi trimis pe un registru, pe cnd expresia 1+4 necesit mai multe locaii de memorie). Evaluarea strict are implementri directe pe hardware. Ordinea evalurii este clar pentru programator: fiecare argument trebuie s fie evaluat nainte de invocarea corpului funciei.
Calculul lambda furnizeaz o baz teoretic mai puternic pentru limbajele ce folosesc evaluarea non-strict. Un evaluator non-strict poate recunoate c o subexpresie nu mai trebuie s fie evaluat. De exemplu, se d definiia:
multiply(0, x) = 0; multiply(n, x) = x + multiply(n-1, x); f(0) = 1; f(n) = n * f(n-1); i expresia multiply(0, f(1000000)) un evaluator strict va trebui s efectueze un numr de pai de ordinul a 1.000.000 pentru a gsi valoarea lui f(1000000). Un evaluator non-strict poate utiliza definiia nmulirii nti, reducnd ntreaga expresie la 0 nainte de a ncerca s calculeze f(1000000).
Evaluarea non-strict poate utiliza cele de mai sus pentru a permite structuri de date infinite. De exemplu, n Haskell, dat fiind definiia
take 0 (list) = [] -- cnd n este 0, ntoarce o list vid take n (x:list) = x : (take (n-1) list) -- altfel, ntoarce primul element i n-1 dintre urmtoarele elemente expresia take 4 (evens 0)
returneaz rapid [0,2,4,6]. n evaluarea strict, evens ar trebui s fie complet evaluat pentru a se apela take, dar deoarece evens este recursiv, nu se va termina niciodat. Cu evaluarea non-strict, funcia take 4 foreaz doar evaluarea a patru elemente din evens 0 celelalte elemente nemaifiind inspectate sau evaluate. Evaluarea lazy Nevoia de o form mai eficient de evaluare non-strict a condus la dezvoltarea evalurii lazy, un tip de evaluare non-strict, n care evaluarea iniial a unui argument este partajat de-a lungul secvenei de evaluare. n consecin, un argument (cum ar fi g(1, 4) n exemplul de mai sus) nu este evaluat dect o dat. n cazul evalurii lazy, expresiile se trimit funciilor subordonate ca referine la arbori de expresii ale cror valori nu au fost calculate nc. Cnd unul dintre arborii de expresie trebuie expandat, arborele de expresie i reine rezultatul, evitnd astfel recalcularea aceleiai expresii a doua oar. n exempul iniial, aceasta ar funciona dup cum urmeaz: = f(g(1, 4)) = g(1, 4)^2 + g(1, 4) + 1 Apoi trebuie evaluat g(1, 4). Acesta se poate calcula o singur dat, rezultnd: g(1, 4) =1+4 =5 Apoi, fiindc ambele referine la g(1, 4) sunt referine la aceeai expresie pur, ambele i cunosc valoarea ca fiind 5. Aceasta nseamn c valoarea lor este calculat o singur dat, dei ele sunt transmise funciei f simbolic. = 5^2 + 5 + 1 = 25 + 5 + 1 = 31
Evaluarea lazy tinde s fie utilizat implicit n limbajele funcionale pure, ca Miranda, Clean i Haskell.
Ce este o Monad?
O Monad este o cale care structura calculele ca valori si secvenele de calculi ce utilizeaz aceste valori . Ele permit construirea de calculi folosind blocuri secveniale care la rndul lor pot fi secvene de calcul. O monad poate fi considerate ca o strategie pentru a combina mai multe calculi ntr-un calcul complex. Tipul de data Maybe Tipul de data Maybe este un tip care poate eua sau returna o valoare. data Maybe a = Nothing | Just a mydiv:: Float -> Float -> Maybe Float mydiv x 0 = Nothing mydiv x y = Just (x/y)
Tiipul Maybe sugereaz combinarea a dou calcule astfel: Fie dou calcule A i B. Presupunem c , calculul B depinde de calculul A. Atunci calculul B va avea ca rezultat : - Nothing , dac calculul A sau B nu produce nimic. Dac ambele calcule produc ceva atunci calculul va produce rezultatul calculului B , dependent de calculul a.
Constructori de tip
Un constructor de tip este o definiie de tip parametrizat ce foloseste tipuri polimorfe. Exemplu :
data Maybe a = Nothing | Just a
O data se poate construe aplicand aplicnd constructorul de data (Just) unei valor. Un tip se poate construi aplicnd constructorul de tip (Maybe) unui tip. Exemplu :
tara = Just England Maybe Int, Maybe String
Tipurile polimorfe sunt nite containere care pot conine valori de diferite tipuri. De exemplu Maybe String poate fi un container Maybe ce conine dou tipuri de valori String sau Nothing. Se folosesc variabile tip cu constructorii de tip pentru a descrie trsturile abstracte ale unui calcul. Exemplu Maybe a este tipul tuturor constructorilor care pot returna o valoare de tip a sau Nothing.
Monada n Haskell
Monadele sunt foarte folositoare n Haskell, dar conceptul este de obicei dificil de neles. Iniial monadele au fost introduse n Programarea Funcional pentru a efectua aciuni de tip input/output. Pna la urm evaluarea lazy const n faptul c ordinea efecturii calculelor este imprevizibil. Dar monadele nu sunt limitate doar la input/output, ele pot modela orice limbaj imperativ. O monad este definit de trei lucruri : -
M este un constructor de tip polimorfic. Operatorul >>== este o funcie polimorfic definita n biblioteca standard (clasa Monad). Ct despre return , calculele monadice trebuie sa porneasca de la o valoare iniial. Avantajul practic al folosirii monadelor n limbajul Haskell este faptul c ele definesc un fel de sublimbaj al Haskell-ului cu nuana imperativ. Este ca un fel de limbaj imperativ inclus in limbajul Haskell. Constructorul de tip Monad definete un tip de calcul.Funcia return creaza instane ale acestui tip. Operatorul >>= combin calcule de acest tip pentru a obine calcule mai complexe de tipul respectiv.
Constructorul de tip [] folosit pentru crearea listelor este i el tot o monad. Funcia return creaz lista Singleton. return x = [x] Operaia de legare pentru liste creaz o noua list coninnd rezultatul aplicrii funciei tuturor valorilor listei originale. l >>= f = concatMap f l concatMap :: (a -> [b]) -> [a] -> [b]
Clasa Monad
n Haskell exist o clas standard Monad care definete numele si signatura funciilor return i >>=. Se recomand ca monadele utilizator sa fie instane ale acestei clase. Monada Maybe este instana a acestei clase. instance Monad Maybe where Nothing >>= f = Nothing (Just x) >>= f = f x return = Just
Notaia do
Notaia do este o alternativ n utilizarea funciilor monadice. Monadele ofer prin notaia do posibilitatea de a crea calcule n stil imperativ in cadrul programelor funcionale. mothersPaternalGrandfather s = do { m <- mother s; gf <- father m; father gf }
Monada I/O
Programele pur funcionale sunt incompatibile cu operaiile de intrare/ieire. Soluia pentru aceast problem este monada I/O. Calculele monad I/O se numesc aciuni de intrare/iesire.
Aciunile intrare/iesire
O valoare de tip I/O este o aciune care va avea efect atunci cnd este executat. n Haskell, o valoare program este valoarea variabilei main din modulul Main. Dac aceast valoare este de tip I/O a, atunci va fi executat ca o aciune. Dac este de alt tip atunci valoarea sa va fi afiat.
readFile :: FilePath -> IO String 5) Scriere String n fiier writeFile :: FilePath -> String -> IO ()