Sunteți pe pagina 1din 31

Programare funct, ională

Introducere în programarea funct, ională folosind Haskell


C04

Ana Iova
Denisa Diaconescu

Departamentul de Informatică, FMI, UB

1
Currying
Currying

Currying este procedeul prin care o funct, ie cu mai multe argumente


este transformată într-o funct, ie care are un singur argument s, i
întoarce o altă funct, ie.

• In Haskell toate funct, iile sunt în forma curry, deci au un singur


argument.

• Operatorul → pe tipuri este asociativ la dreapta, adică tipul


a1 → a2 → · · · → an îl gândim ca
a1 → (a2 → · · · (an−1 → an ) · · · ).

• Aplicarea funct, iilor este asociativă la stânga, adică


expresia f x1 · · · xn o gândim ca (· · · ((f x1 ) x2 ) · · · xn ).

2
Funct, iile curry si uncurry s, i mult, imi

Prelude > : t curry


curry : : ( ( a , b ) −> c ) −> a −> b −> c

Prelude > : t uncurry


uncurry : : ( a −> b −> c ) −> ( a , b ) −> c

Exemplu:
f : : ( I n t , S t r i n g ) −> S t r i n g
f ( n , s ) = take n s

Prelude > l e t c f = curry f


Prelude > : t c f
c f : : I n t −> S t r i n g −> S t r i n g
Prelude > f ( 1 , " abc " )
"a"
Prelude > c f 1 " abc " 3
"a"
Funct, ii în matematică

• Fie f : A × B → C o funct, ie. În mod uzual scriem


f (x , y ) = z unde x ∈ A , y ∈ B s, i z ∈ C.

• Pentru x ∈ A (arbitrar, fixat) definim


fx : B → C, fx (y ) = z dacă s, i numai dacă f (x , y ) = z.
Funct, ia fx se obt, ine prin aplicarea part, ială a funct, iei f .

not
• Dacă notăm B → C = {h : B → C | h funct, ie}
observăm că fx ∈ B → C pentru orice x ∈ A .

• Asociem lui f funct, ia cf : A → (B → C ), cf (x ) = fx .

• Vom spune că funct, ia cf este forma curry a funct, iei f .

4
Quiz time!
Seria 23: https://questionpro.com/t/AT4qgZvHuO

Seria 24: https://questionpro.com/t/AT4NiZu3KB

Seria 25: https://questionpro.com/t/AT4qgZvHuP

5
Agregarea elementelor dintr-o listă - fold
Exemplu - Suma

Definit, i o funct, ie care dată fiind o listă de numere întregi calculează


suma elementelor din listă.

Solut, ie recursivă
sum : : [ I n t ] −> I n t
sum [ ] = 0
sum ( x : xs ) = x + sum xs

Prelude > sum [ 1 , 2 , 3 , 4 ]


10

6
Exemplu - Produs

Definit, i o funct, ie care dată fiind o listă de numere întregi calculează


produsul elementelor din listă.

Solut, ie recursivă
product : : [ I n t ] −> I n t
product [ ] = 1
product ( x : xs ) = x * product xs

Prelude > product [ 1 , 2 , 3 , 4 ]


24

7
Exemplu - Concatenare

Definit, i o funct, ie care concatenează o listă de liste.

Solut, ie recursivă
concat : : [ [ a ] ] −> [ a ]
concat [ ] = []
concat ( xs : xss ) = xs ++ concat xss

Prelude > concat [ [ 1 , 2 , 3 ] , [ 4 , 5 ] ]


[1 ,2 ,3 ,4 ,5]

Prelude > concat [ " con " , " ca " , " t e " , " na " , " r e " ]
" concatenare "

8
Funct, ia foldr

foldr :: (a −> b −> b) −> b −> [a] −> b

Date fiind o funct, ie de actualizare a valorii calculate cu un element


curent, o valoare init, ială, s, i o listă, calculat, i valoarea obt, inută prin
aplicarea repetată a funct, iei de actualizare fiecărui element din listă.

9
Funct, ia foldr

foldr :: (a −> b −> b) −> b −> [a] −> b

Solut, ie recursivă
f o l d r : : ( a −> b −> b ) −> b −> [ a ] −> b
foldr f i [ ] = i
f o l d r f i ( x : xs ) = f x ( f o l d r f i xs )

Solut, ie recursivă cu operator infix


f o l d r : : ( a −> b −> b ) −> b −> [ a ] −> b
f o l d r op i [ ] = i
f o l d r op i ( x : xs ) = x `op` ( f o l d r f i xs )

10
Exemplu — Suma

Solut, ie recursivă
sum : : [ I n t ] −> I n t
sum [ ] = 0
sum ( x : xs ) = x + sum xs

Solut, ie folosind foldr


foldr :: (a −> b −> b) −> b −> [a] −> b
sum : : [ I n t ] −> I n t
sum xs = f o l d r ( + ) 0 xs

Exemplu
f o l d r ( + ) 0 [ 1 , 2 , 3 ] == 1 + ( 2 + ( 3 + 0 ) )

11
Exemplu — Produs

Solut, ie recursivă
product : : [ I n t ] −> I n t
product [ ] = 1
product ( x : xs ) = x * product xs

Solut, ie folosind foldr


foldr :: (a −> b −> b) −> b −> [a] −> b
product : : [ I n t ] −> I n t
product xs = f o l d r ( * ) 1 xs

Exemplu
f o l d r ( * ) 1 [ 1 , 2 , 3 ] == 1 * ( 2 * ( 3 * 1 ) )

12
Exemplu — Concatenare

Solut, ie recursivă
concat : : [ [ a ] ] −> [ a ]
concat [ ] = []
concat ( xs : xss ) = xs ++ concat xss

Solut, ie folosind foldr


foldr :: (a −> b −> b) −> b −> [a] −> b
concat : : [ I n t ] −> I n t
concat xs = f o l d r ( + + ) [ ] xs

Exemplu
f o l d r ( + + ) [ ] [ " Ana " , " are " , " mere . " ]
== " Ana " ++ ( " are " ++ ( " mere . " ++ [ ] ) )

13
Exemplu – Suma pătratelor numerelor pozitive

f : : [ I n t ] −> I n t
f xs = sum ( squares ( p o s i t i v e s xs ) )

f : : [ I n t ] −> I n t
f xs = sum [ x * x | x <− xs , x > 0 ]

f : : [ I n t ] −> I n t
f [] = 0
f ( x : xs ) | x > 0 = ( x * x ) + f xs
| otherwise = f xs

14
Exemplu – Suma pătratelor numerelor pozitive

f : : [ I n t ] −> I n t
f xs = f o l d r ( + ) 0 (map s q r ( f i l t e r pos xs ) )
where
sqr x = x * x
pos x = x > 0

f : : [ I n t ] −> I n t
f xs = f o l d r ( + ) 0
(map (\ x -> x * x)
( f i l t e r (\ x -> x > 0) xs ) )

f : : [ I n t ] −> I n t
f xs = f o l d r ( + ) 0 (map ( ˆ 2) ( f i l t e r ( > 0) xs ) )

f : : [ I n t ] −> I n t
f = f o l d r ( + ) 0 . map ( ^ 2 ) . f i l t e r ( >0)
15
Exemplu - Compunerea funct, iilor

În definit, ia lui foldr


f o l d r : : ( a −> b −> b ) −> b −> [ a ] −> b

b poate fi tipul unei funct, ii.

compose : : [ a −> a ] −> ( a −> a )


compose = f o l d r ( . ) i d

Prelude > compose [ ( + 1 ) , ( ^ 2 ) ] 3


10
−− f u n c t i a ( f o l d r ( . ) i d [ ( + 1 ) , ( ^ 2 ) ] ) a p l i c a t a l u i 3

16
Quiz time!
Seria 23: https://questionpro.com/t/AT4qgZvALu

Seria 24: https://questionpro.com/t/AT4NiZvIWL

Seria 25: https://questionpro.com/t/AT4qgZvALw

17
Foldr s, i Foldl
foldr s, i foldl

Date fiind o funct, ie de actualizare a valorii calculate cu un element


curent, o valoare init, ială, s, i o listă, calculat, i valoare obt, inută prin
aplicarea repetată a funct, iei de actualizare fiecărui element din listă.

foldr :: (a −> b −> b) −> b −> [a] −> b


f o l d r op z [ a1 , a2 , a3 , . . . , an ] =
a1 `op` ( a2 `op` ( a3 `op` ( . . . ( an `op` z ) . . . ) ) )

foldl :: (b −> a −> b) −> b −> [a] −> b


f o l d l op z [ a1 , a2 , a3 , . . . , an ] =
( . . . ( ( ( z `op` a1 ) `op` a2 ) `op` a3 ) . . . ) `op` an

18
foldr s, i foldl

Funct, ia foldr
f o l d r : : ( a −> b −> b ) −> b −> [ a ] −> b
foldr f i [ ] = i
f o l d r f i ( x : xs ) = f x ( f o l d r f i xs )

Funct, ia foldl
f o l d l : : ( b −> a −> b ) −> b −> [ a ] −> b
foldl h i [ ] = i
f o l d l h i ( x : xs ) = f o l d l h ( h i x ) xs

19
Suma elementelor dintr-o listă

Definit, i o funct, ie care dată fiind o listă de numere întregi calculează


suma elementelor din listă.

Solut, ie cu foldr
sum = f o l d r ( + ) 0

Cu foldr, elementele sunt procesate de la dreapta la stânga:

sum [x1 , . . . , xn ] = (x1 + (x2 + . . . (xn + 0) . . .)

20
Suma elementelor dintr-o listă

Solutie in care elementele sunt procesate de la stânga la dreapta.

sum : : [ I n t ] −> I n t
sum xs = suml xs 0
where
suml [ ] n = n
suml ( x : xs ) n = suml xs ( n+x )

Elementele sunt procesate de la stânga la dreapta:

suml [x1 , . . . , xn ] 0 = (. . . (0 + x1 ) + x2 ) + . . . xn )

Solut, ie cu foldl
sum : : [ I n t ] −> I n t
sum xs = f o l d l ( + ) 0 xs

21
Inversarea elementelor unei liste

Definit, i o funct, ie care dată fiind o listă de elemente, calculează lista


în care elementele sunt scrise în ordine inversă.

Solut, ie cu foldl
−− f l i p : : ( a −> b −> c ) −> ( b −> a −> c )
−− ( : ) : : a −> [ a ] −> [ a ]
−− f l i p ( : ) : : [ a ] −> a −> [ a ]

rev = f o l d l ( <: >) [ ]


where ( < : > ) = f l i p ( : )

Elementele sunt procesate de la stânga la dreapta:

rev [x1 , . . . , xn ] = (...(([] <:> x1 ) <:> x2 ).....) <:> xn

22
Evaluare lenes, ă. Liste infinite

Putem folosi funct, ile map s, i filter pe liste infinite:


Prelude > i n f = map ( + 1 0 ) [ 1 . . ] −− i n f nu e s t e e v a l u a t
Prelude > take 3 i n f
[11 ,12 ,13]

Limbajul Haskell foloses, te implicit evaluarea lenes, ă


• expresiile sunt evaluate numai când este nevoie de valoarea lor
• expresiile nu sunt evaluate total, elementele care nu sunt
folosite rămân neevaluate
• o expresie este evaluată o singură dată.

În exemplul de mai sus, este acceptată definit, ia lui inf , fără a fi


evaluată. Când expresia take 3 inf este evaluată, numai primele 3
elemente ale lui inf sunt calculate, restul rămânând neevaluate.
23
Evaluare lenes, ă: lista numerelor prime

Vă amintit, i din primul curs:


primes = s i e v e [ 2 . . ]
s i e v e ( p : ps ) = p : s i e v e [ x | x <− ps , mod x p / = 0 ]

Intuitiv, evaluarea lenes, ă funct, ionează astfel:

s i e v e [ 2 . . ] −−>

2 : s i e v e [ x | x <− [ 3 . . ] , mod x 2 / = 0 ] −−>

2 : s i e v e ( 3 : [ x | x <− [ 4 . . ] , mod x 2 / = 0 ] ) −−>

2 : 3 : s i e v e ( [ y | y <−
[ x | x <− [ 4 . . ] , mod x 2 / = 0 ] ,
mod y 3 / = 0 ] )
−−> . . . 24
foldr s, i foldl

https://en.wikipedia.org/wiki/Fold_(higher-order_function)

• foldr poate fi folosită pe liste infinite (în anumite cazuri)


• foldl nu poate fi folosită pe liste infinite niciodată

25
foldr s, i foldl

• foldr poate fi folosită pe liste infinite (în anumite cazuri),


• foldl nu poate fi folosită pe liste infinite niciodată.

Prelude > f o l d r ( * ) 0 [ 1 . . ]
*** Exception: stack overflow

Prelude > take 3 $ f o l d r ( \ x xs −> ( x +1) : xs ) [ ] [1..]


[2 ,3 ,4]
−− f o l d r a f u n c t i o n a t pe o l i s t a i n f i n i t a

Prelude > take 3 $ f o l d l ( \ xs x −> ( x +1) : xs ) [ ] [ 1 . . ]


−− e x p r e s i a se c a l c u l e a z a l a i n f i n i t

26
Quiz time!
Seria 23: https://questionpro.com/t/AT4qgZvHue

Seria 24: https://questionpro.com/t/AT4NiZvIW4

Seria 25: https://questionpro.com/t/AT4qgZvHuf

27
Pe săptămâna viitoare!

28

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