This is an old revision of the document!


Aplicații cu funcții de ordin superior

Scopul laboratorului este de a exersa lucrul cu funcții de ordin superior.

O funcție de ordin superior este o funcție care primește ca argument sau returnează o funcție.

applyTwice f x = f (f x)
adder x = (+x)

foldr & foldl

Două funcții de ordin superior foarte importante sunt foldurile pe liste: foldl și foldr. Aceasta combină, în mod recursiv, elementele unei liste cu o valoare default, pentru a obține un rezultat. Diferența principală între ele constă în sensul de parcurgere: foldl (“fold left”) începe din stânga listei, iar foldr (“fold right”) începe din dreapta listei.

Prelude> foldl (^) 1 [2, 2, 2]     -- (((1 ^ 2) ^ 2) ^ 2)
1
Prelude> foldr (^) 1 [2, 2, 2]     -- (2 ^ (2 ^ (2 ^ 1)))
16
Prelude>

Dacă operația aleasă este comutativă și asociativă, rezultatul vor fi aceleași, doar ordinea operațiilor fiind diferită.

Observați că și tipul funcției primită ca argument diferă; foldl trimite elementele listei ca al doilea parametru, iar foldr ca prim parametru.

foldr (:) [] l         -- întoarce o lista identică cu l
foldl (flip (:)) [] l  -- întoarce inversul listei l

Tipurile acestor funcții sunt, deci:

foldl :: (b -> a -> b) -> b -> [a] -> b
foldr :: (a -> b -> b) -> b -> [a] -> b

Contemplați aceste tipuri până vă este clar de ce sunt așa.

În Haskellul modern, tipul acestor funcții este și mai generic, funcționând pe mai multe tipuri de structuri de date considerate “foldable”, nu doar pe liste:
Prelude> :t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
Prelude> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

(Mai multe detalii despre notații ca => și t a la cursurile/laboratoarele viitoare).

Tail-recursion și evaluare leneșă

O privire la implementarea celor două folduri:

foldl _ e [] = e
foldl f e (x:xs) = foldl f (f e x) xs
 
foldr _ e [] = e
foldr f e (x:xs) = f x (foldr f e xs)

dezvăluie o altă diferență: foldl este tail-recursive, foldr nu. Concluzia naivă este că foldl este mai eficient, deci mai “bun”. Situația însă este mai complicată din cauza evaluării leneșe din Haskell. foldr permite lucrul cu liste infinite, iar foldl de fapt nu oferă niciun avantaj cu privire la spațiul de stivă utilizat; mai multe detalii la cursuri/laboratoare despre evaluare leneșă.

Vizualizare

Următoarea este o vizualizare a rezultatului următoarelor două aplicări (pentru oricare f și z):

foldr f z [1, 2, 3, 4, 5]
foldl f z [1, 2, 3, 4, 5]

Alte funcții de ordin superior des întâlnite: map, filter, zipWith, flip.

  1. Fie două matrici reprezentate ca liste de liste. În rezolvarea exercițiilor de mai jos, puteți folosi doar funcții de ordin superior (împreună cu take și drop). Implementați funcții care să returneze:
    1. linia i dintr-o matrice
    2. elementul (i, j) dintr-o matrice
    3. suma a două matrici
    4. transpusa unei matrici
    5. produsul a două matrici
  2. Fie o imagine reprezentată ca o matrice de caractere (numiți, în continuare, “pixeli”). Considerăm că avem două tipuri de pixeli: '*' și ' '. Implementați următoarele funcții:
    1. flip orizontal
    2. flip vertical
    3. rotație de 90 de grade în sens trigonometric
    4. rotație de 90 de grade în sens invers trigonometric
    5. negativul ('*' devine ' ', iar ' ' devine '*')
    6. scalarea unei imagini cu x unități
    7. alipirea a două imagini (cu aceeași înălțime) pe orizontală
    8. alipirea a două imagini (cu aceeași lungime) pe verticală
    9. crop vertical de la linia x la linia y
    10. crop orizontal de la coloana x la coloana y

Lab 3 - schelet

În afară de asserturile din schelet, aveți la dispoziție funcții și variabile ajutătoare în fișierul Helper.hs. Aveți matricile m1 și m2, precum și rezultatul sumei și al produsului acestora, plus o imagine img.

Pentru afișarea lizibilă a unei matrici, aveți funcția displayMat, iar pentru imagine displayImg; acestea ar trebui să vă ajute cu testarea.

*Lab3> displayMat m1
1   2   3
4   5   6
7   8   9
*Lab3> displayImg img
        ***** **            ***** **
     ******  ****        ******  ****
    **   *  *  ***      **   *  *  ***
   *    *  *    ***    *    *  *    ***
       *  *      **        *  *      **
      ** **      **       ** **      **
      ** **      **       ** **      **
    **** **      *      **** **      *
   * *** **     *      * *** **     *
      ** *******          ** *******
      ** ******           ** ******
      ** **               ** **
      ** **               ** **
      ** **               ** **
 **   ** **          **   ** **
***   *  *          ***   *  *
 ***    *            ***    *
  ******              ******
    ***                 ***
*Lab3>