Terzo esempio spiegato.

import Graphics.Gloss

main = displayInWindow "terzo esempio" (600,500) (0,0) white .
   Pictures . map f $ [100,99.9 .. 5]
   where f y    = Rotate (10*y) 
                . Translate 0 y 
                . Color (makeColor 0 (y/100) (1 - y/100) (y/100)) 
                $ ThickCircle y y

Per prima cosa notiamo una nuova parola chiave where. Con essa possiamo usare dei nomi nelle nostre definizioni che specifichiamo dopo il where.
Nel terzo esempio abbiamo usato il nome ‘f’ definendolo in seguito.

f x = g (g x) where g x = x * x

Questo stralcio si legge “f di x è uguale a g di g di x dove g x è uguale a x per x”.
La definizione di ‘f’ non ci da problemi e segue lo stile composizionale spiegato nell’articolo precedente. Infatti abbiamo aggiunto una funzione alla catena delle composizioni, un costruttore che aggiunge il colore.
La funzione ‘f’ crea per ogni ‘y’ un cerchio pieno di raggio ‘y’ di colore verde per ‘y/100’ , blu per ‘1-y/100’ e trasparenza ‘y/100’, spostato lungo la verticale di ‘y’ pixel e ruotato di ’10*y’ gradi intorno all’origine.
Ora introduciamo map che è una funzione di ordine superiore (HOF) , la seconda che incontriamo. Le HOF sono funzioni che prendono funzioni come argomento. La prima era il (.).
Le HOF sono strumenti potenti che è necessario imparare per dominare i linguaggi funzionali e comunque sono molto utili per riutilizzare il codice anche negli altri.

Prelude> :t map
map :: (a -> b) -> [a] -> [b]

Il primo argomento di map una funzione da ‘a’ a ‘b’ che quindi possono essere qualsiasi tipo.
Il secondo e ultimo argomento è una lista di ‘a’. Il risultato una lista di ‘b’.
Abbiamo già capito che map applica la funzione passata a tutti gli elementi della lista, ottenendo una nuova lista.

Prelude> map not [True,False,False,True]
[False,True,True,False]

La prima considerazione è che map si ottiene facilmente con la list comprehension che invece permette anche altro.

Prelude> [not x | x <- [True,False,False,True]]
[False,True,True,False]

La seconda è che map è molto limitato, infatti non riusciamo a calcolare un valore che considera insieme tutti gli elementi della lista.
Per esempio non siamo in grado di sommare gli elementi di una lista.
Ora completiamo la nostra conoscenza della list comprehension, introducendo il concetto di guardia, ma per arrivarci facciamo il percorso contrario a quello fatto per map.
Una nuova HOF: filter.

Prelude> :t filter
filter :: (a -> Bool) -> [a] -> [a]

filter riceve una funzione giudice e una lista . Con la funzione seleziona gli elementi giudicati True e li mette nella nuova lista creata.

Prelude> filter odd [1..20]
[1,3,5,7,9,11,13,15,17,19]

Per sicurezza controlliamo che tipo di odd sia compatibile con il primo argomento di filter, che restituisce True se il suo argomento è dispari

Prelude> :t odd
odd :: Integral a => a -> Bool

Ora scriviamo una funzione che ci restituisce il carattere relativo ai numeri dispari tra 30 e 70

Prelude Data.Char> map chr . filter odd $ [30 .. 70]
"\US!#%')+-/13579;=?ACE"

La list comprehension permette di introdurre una guardia che agisce esattamente come filtro.

Prelude Data.Char> [chr x | x <- [30 .. 70], odd x]
"\US!#%')+-/13579;=?ACE"

La potenza della list comprehension viene dalla possibilità di nidificare più generatori

Prelude Data.Char> [x + y | x <- [1 .. 9], y <- [1 .. 9],  odd x && even y]
[3,5,7,9,5,7,9,11,7,9,11,13,9,11,13,15,11,13,15,17]

Per finire introduciamo un costrutto simile a where che per ora utilizzeremo senza approfondirne le differenze con where.
where posticipa le definizioni mentre let … in le anticipa. Una differenza per noi sostanziale è che lo possiamo utilizzare in ghci per i nostri esempi.

Prelude Data.Char> let f x = x `mod` 3 == 0 in filter f [1..30]
[3,6,9,12,15,18,21,24,27,30]

Qui definiamo una funzione ‘f’ che ritorna True quando il suo argomento è multiplo di 3 e poi la utilizziamo come argomento di filter.
Ed ecco il nostro terzo esempio riscritto con let … in

import Graphics.Gloss

main = let 
	f y    = Rotate (10*y) . Translate 0 y
               . Color (makeColor 0 (y/100) (1 - y/100) (y/100))
               $ ThickCircle y y
	p = Pictures $ map f [100,99.9 .. 5]	
	in displayInWindow "terzo esempio" (600,500) (0,0) white p
Annunci

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...