Sunteți pe pagina 1din 10

Monade n Programare Funcional

Introducere n Programare Func ional


Programarea funcional este o paradigm de programare care trateaz caluclul ca o evaluare de funcii matematice i evita starea de date muabile. Se pune accent pe aplicarea de funcii i nu pe schimbarea starilor ( ca in programarea imperativ). Modelul matematic al progrmarii funcionale il reprezinta calculul lambada, practic limbajele de programare funcionala moderne pot fi considerate ca o extensie a calculului lambada. Printre limbajele de programare funcionala moderne se numara : Erlang,Haskell si ML . Limbajele de programare pur funcionale sunt promovate in mediile academice i sunt rar folosite in dezvoltarea de software comercial. Multe limbaje de programare nefuncionale ( C, C++) pot fi facute sa aiba un comportament funcional prin folosirea pointerilor la funcii. Funciile sunt numite de nivel nalt sau funcionale daca pot primi ca parametru o funcie si returneaz alt funcie (exemplu derivata si primitiva in analiza matematic). Noiunea de funcional este strans legata de noiunea de duncie nti prin faptul c ambele permit primirea de funcie ca parametru i returnarea de funcie ca valoare. Diferena ntre cele dou este foarte subtil , funcionalele descriu un concept matematic de funcii care opereaza pe late funcii , iar funcia de clas ntai este un termen din informatic care descrie entitai din limbajele de programare care nu au restricii de utilizare . Funciile (expresiile pur funcionale) nu au memorie sau efecte laterale i au cateva proprietai utile care pot fi folosite n optimizarea codului : o Dac nu se utilizeaz rezultatul unei expresii pure, el poate fi eliminat fr a afecta alte expresii. o Dac nu exist dependene de date ntre dou expresii pure, atunci ordinea evalurii lor poate fi inversat, sau ele pot fi evaluate n paralel i nu pot interfera una cu cealalt .

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.

Avantajele evalurii stricte

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.

Avantajele evalurii non-stricte


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

evens n = n : [evens (n+2)] -- o "list infinit" de numere pare ncepnd cu n

-- Funcia "take n" ntoarce primele n elemente ale argumentului

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.

Monade n Programare Func ional


Cum construim programe interactive n HASKELL?(citire de la tastatur , citire din fisiere , etc)
n Haskell valorile pure sunt separate de aciuni n dou moduri : 1. Tipuri O expresie de tip IO a are associate execuiei sale eventuale aciuni ultima dintre ele fiind returnarea unei valori de tip a, 2. Sintax Construcia sintactic do realizeaz o aciune care este o secven de aciuni elementare.

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.

Proprieti fundamentale ale monadelor


1. Modularitate Calculele complexe sunt compuse din calculi simple. Strategiile de combinare a calculelor sunt separate de calculele n sine. 2. Flexibilitate Caluclele scrise cu monade sunt mai adaptabile ca cele scrise fara monade. 3. Izolare Monadele permit crearea de calcul imperativ care rmn izolate de corpul principal al programului functional.

Constructori de tip
Un constructor de tip este o definiie de tip parametrizat ce foloseste tipuri polimorfe. Exemplu :
data Maybe a = Nothing | Just a

Maybe este constructor de tip Nothing i Just sunt constructori de date

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 : -

un tip constructor M o funcie return un operator >>== (pronunat bind)

Funcia i operatorul trebuie s aib tipuri :


return :: a -> M a (>>=) :: M a -> ( a -> M b ) -> M b

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.

Acces la componentele unei date


Tipul de dat Point: data Point = Pt Float Float let p = Pt 3.2 5.4 Accesul la componente poate fi fcut prin funcii: pointx :: Point -> Float pointx (Pt x _) = x pointx p Mai comod declaraia echivalent: data Point = Pt {pointx, pointy :: Float} pointx :: Point -> Float pointy :: Point -> Float

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.

Aciuni I/O predefinite


1) Introducerea unui caracter de la tastatur getChar :: IO Char 2) Scrie un caracter la terminal

putChar :: Char -> IO () 3) Introducerea unei linii de la tastatur

getLine :: IO String 4) Citirea unui fiier ca i String

readFile :: FilePath -> IO String 5) Scriere String n fiier writeFile :: FilePath -> String -> IO ()

S-ar putea să vă placă și