Secondo esempio spiegato.

Per ragionare meglio sul secondo esempio, lo riscriviamo scomponendo l’espressione che determina il valore di tipo Picture.

import Graphics.Gloss
f y = Rotate (2*y) . Translate 0 y $ Circle y
ps = [f y | y <- [5,10 .. 100]]
main = displayInWindow "secondo esempio" (500,600) (0,0) white $ Pictures ps

Per caricare questa definizione in ghci, si deve salvare il codice in un file “esempio2.hs”, aprire ghci e usare il comando :load

Prelude> :load esempio2
[1 of 1] Compiling Main             ( esempio2.hs, interpreted )
Ok, modules loaded: Main.
*Main> 

Ora possiamo interrogare l’interprete per conoscere i tipi dei nomi caricati

*Main> :t f
f :: Float -> Picture
*Main> :t ps
ps :: [Picture]

Il tipo di f è lo stesso di Circle. Infatti il significato dell’espressione è: un cerchio di raggio y , spostato di y pixel in alto e ruotato intorno all’origine di 2*y gradi. Quindi una funzione che da qualsiasi y di tipo Float crea una Picture.
Andiamo piano. Prima di tutto eliminiamo il . e l’$ che sono combinatori e ci complicano la vita all’inizio. Utilizziamo le parentesi per isolare le sottoespressioni.

f y = Rotate (2*y) (Translate 0 y (Circle y))

L’espressione è equivalente ma meno idiomatica. Osseviamo i tipi dei 3 costruttori in gioco.

*Main> :t Circle
Circle :: Float -> Picture
*Main> :t Translate
Translate :: Float -> Float -> Picture -> Picture
*Main> :t Rotate
Rotate :: Float -> Picture -> Picture
*Main> 

C’è qualcosa che distingue nettamente Circle dagli altri. Infatti Circle è l’unico che pare costruisca una Picture, gli altri la trasformano. Ma in haskell le cose non si trasformano, le cose si creano e basta. Allora si capiscono meglio i tipi di Translate e Rotate. Translate vuole i due spiazzamenti orizzontale e verticale e una Picture, così facendo esso è un’altra Picture. Stesso vale per Rotate che vuole un angolo ed una Picture, risultando in una nuova Picture.

Questa corrispondenza tra la descrizione e il codice è la forza dei datatype ricorsivi: essi sono un buon modello per un linguaggio descrittivo.
I datatype ricorsivi contengono valori del tipo che stanno defininendo nella definizione dei propri costruttori.
Dobbiamo capire che essi sono semplicemente un valore, come 42 o “primo esempio” o 12.34, ma descrivono un valore che ha una struttura complessa.
Scriviamo alcuni valori di tipo Picture.

*Main> :t Translate 10 10 (Circle 10)
Translate 10 10 (Circle 10) :: Picture
*Main> :t Rotate 40 (Circle 20)
Rotate 40 (Circle 20) :: Picture
*Main> :t Translate 10 10 (Rotate 40 (Circle 20))
Translate 10 10 (Rotate 40 (Circle 20)) :: Picture
*Main> 

Il secondo ostacolo è il valore ps.

ps :: [Picture]

Il suo tipo si legge “Lista di valori di tipo Picture”. Purtroppo la lista è il primo tipo parametrico che incontriamo, ed ha una sintassi un po speciale che confonde molto le idee. Una lista è un tipo ricorsivo esattamente come Picture, ma è polimorfo, ovvero è di tipo diverso a seconda del tipo degli elementi che contiene.
Questa cosa riflette il suo significato, una lista di numeri è diversa da una lista di lettere, diversa da una lista di Picture e così via. Siccome la lista è omni presente nel codice haskell, una sintassi speciale è stata introdotta, in particolare il suo tipo si scrive [] e il suo parametro, il tipo degli elementi che contiene si scrive all’interno delle quadre. Anche il costruttore di valori lista si scrive [] e l’elenco dei valori contenuti si mette dentro separato da virgole.

*Main> :t ['a','b','c','d']
['a','b','c','d'] :: [Char]

Questa era una lista di caratteri. Il suo tipo [Char] si può scrivere [] Char. Il valore è stato costruito con parentesi quadre e elementi separati da virgole.
Nell’esempio ho usato una sintassi speciale per le liste (e non solo) che si chiama list comprehension e un operatore anch’esso speciale che genera sequenze dati gli estremi.
Vediamo prima l’operatore .

Prelude> :t ['a' .. 'z']
['a' .. 'z'] :: [Char]
Prelude> [1 .. 10]
[1,2,3,4,5,6,7,8,9,10]
Prelude> [1,3 .. 10]
[1,3,5,7,9]
Prelude> [10,8 .. -10]
[10,8,6,4,2,0,-2,-4,-6,-8,-10]
Prelude> 

E ora la list comprehension.

Prelude> [x * 2 | x <- [1..10]]
[2,4,6,8,10,12,14,16,18,20]

L’operazione costruisce una lista moltiplicando per 2 tutti gli elementi di [1 .. 10]. Prima della barra verticale scriviamo l’espressione che descrive un elemento della lista, dopo la barra descriviamo l’assegnazione degli elementi ai nomi che appaiono nell’espressione.
Nell’esempio sopra x * 2 impone che un elemento è il doppio del valore del nome x. Mentre x <- [1 .. 10] impone che il nome x assuma i valori da 1 a 10 nell’espressione dell’elemento.


Prelude> [(x,y) | x <- ['a' .. 'c'], y <- [1 .. 3]]
[('a',1),('a',2),('a',3),('b',1),('b',2),('b',3),('c',1),('c',2),('c',3)]

Qui creiamo delle coppie dette tuple. Da notare che gli assegnamenti alla ‘x’ e alla ‘y’ non avvengono in parallelo , ma ogni elemento della ‘x’ viene accoppiato con ogni elemento ‘y’.

Tornando a ps, ps è una lista di elementi creati applicando la funzione ‘f’ ad ogni ‘y’ dove ‘y’ varia tra 5 e 100 con passo 5. Ma la funzione ‘f’ genera una Picture da un Float, quindi i valori assegnati a ‘y’ sono Float e ps è una lista di Picture.

Possiamo vedere i primi valori di ps che sono i cerchi che compongono la nostra figura.

*Main> take 3 ps
[Rotate 10.0 (Translate 0.0 5.0 (Circle 5.0)),Rotate 20.0 (Translate 0.0 10.0 (Circle 10.0)),Rotate 30.0 (Translate 0.0 15.0 (Circle 15.0))]

Per finire esaminiamo il costruttore Pictures, infatti l’ultimo argomento di displayInWindow deve essere di tipo Picture, mentre ps è di tipo [Picture].

*Main> :t Pictures
Pictures :: [Picture] -> Picture
*Main> :t ps
ps :: [Picture]
*Main> :t Pictures ps
Pictures ps :: Picture

Esattamente il necessario per accontentare displayInWindow.

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