Primi passi spiegati

Nell’articolo precedente abbiamo introdotto la libreria gloss per accompagnare il percorso sulla programmazione in haskell con qualcosa di concreto.
Ora, esaminando i tre stralci di codice , cerchiamo di capire le basi.
Tutti i programmi di un certo livello si appoggiano ad altri di livello inferiore. Tutti i file contenenti codice si dicono moduli. Nelle prime righe di ogni modulo sono inserite le dipendenze dagli altri.
La parola speciale è import seguita dal nome del modulo che contiene le definizioni che intendiamo utilizzare.
Nei nostri esempi abbiamo importato il modulo Graphics.Gloss. Questo modulo esporta varie definizioni che ci servono a disegnare.
Negli esempi abbiamo una sola definizione a livello di file, quella del nome main.
Ad esso viene associata la funzione displayInWindow con i suoi parametri.
In haskell tutti i nomi che iniziano con lettera minuscola hanno un tipo associato, che determina la correttezza nell’utilizzo.
Dalla documentazione sulla funzione displayInWindow, essa riceve 5 argomenti: il nome della finestra, la grandezza della finestra, le coordinate dell’angolo alto sinistro, il colore di fondo e infine un valore di tipo Picture che definisce il disegno.
Nel primo esempio il valore di tipo Picture è Circle 100. Circle è una funzione costruttore di valori.
Per costruire un valore di tipo Picture possiamo usare uno qualsiasi dei costruttori del suo datatype, quindi Blank, Circle, Polygon e gli altri, ognuno corredato dai suoi argomenti di tipo corretto.
Per esaminare meglio usiamo ghci, l’interprete di ghc.
L’interprete non è potente come il compilatore, ma è molto flessibile e istruttivo.
Si lancia da riga di comando.

paolino@paolino-desktop:~$ ghci
GHCi, version 7.2.1: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
Prelude> import Graphics.Gloss
Prelude Graphics.Gloss> :type Circle
Circle :: Float -> Picture
Prelude Graphics.Gloss> :info Circle
data Picture = ... | Circle Float | ...
  	-- Defined in Graphics.Gloss.Data.Picture

Qui sopra ho riportato una sessione ghci dove ho importato Gloss, ho chiesto il tipo e le informazioni riguardanti Circle.
Come possiamo notare il tipo di Circle è Float -> Picture, che si legge “dato un valore di tipo Float, produce un valore di tipo Picture”. Dalla documentazione apprendiamo che il valore di tipo Float corrisponde al raggio del cerchio. Il simbolo :: si legge “è di tipo”.
Mentre al simbolo = corrisponde una definizione, il simbolo :: corrisponde ad una firma.

Prelude Graphics.Gloss> :t displayInWindow 
displayInWindow
  :: String -> (Int, Int) -> (Int, Int) -> Color -> Picture -> IO ()

Continuando la nostra ispezione notiamo i tipi degli argomenti di displayInWindow che corrispondono al significato dato prima. Controlliamo la coerenza del primo esempio.

Prelude Graphics.Gloss> :t "primo esempio"
"primo esempio" :: [Char]
Prelude Graphics.Gloss> :i String
type String = [Char] 	-- Defined in GHC.Base
Prelude Graphics.Gloss> :t (100,100)
(100,100) :: (Num t, Num t1) => (t, t1)
Prelude Graphics.Gloss> :t (0,0)
(0,0) :: (Num t, Num t1) => (t, t1)
Prelude Graphics.Gloss> :t white
white :: Color
Prelude Graphics.Gloss> :t Circle 100
Circle 100 :: Picture
Prelude Graphics.Gloss> 

Non è andata benissimo, ma su qualcosa ci siamo da subito, white è di tipo Color , e Circle 100 è di tipo Picture. Gli ultimi due argomenti di displayInWindows sono corretti.

Per il primo ho dovuto chiedere informazioni rispetto a String, e , per fortuna il mistero è risolto String è definito come [Char]. Qui si introduce il concetto di sinonimo di tipo. La parola magica è type.

type String = [Char]

Quindi String e [Char] sono lo stesso tipo.
Se continuiamo l’indagine le cose si complicano e si introduce la omni presente struttura dei programmi funzionali, la lista. Infatti [Char] si legge “lista di caratteri”, ma rimandiamo la cosa, per ora, visto che non ci mettiamo a smontare il valore “primo esempio”.

Per gli argomenti dimensione e piazzamento della finestra, i risultati dell’interrogazione sono imprevisti.

Prelude Graphics.Gloss> :t (300,300)
(300,300) :: (Num t, Num t1) => (t, t1)

Ci aspettavamo

(300,300) :: (Int, Int)

, invece l’interprete ci ha restituito

(t,t1)

lasciandoci capire che il tipo di 300 non è fissato. In compenso ha aggiunto una parte nuova nella risposta

(Num t, Num t1) => 

che si legge “se t è istanza della classe Num e t1 è istanza della classe Num, allora …”.
Senza entrare nelle classi di tipi, cerchiamo di capire il problema.
L’argomento di Circle nel primo esempio è 100, ma Circle è di tipo Float -> Picture, quindi 100 è di tipo Float quando lo mettiamo dopo Circle, invece se lo mettiamo come argomento di displayInWindow diventa di tipo Int. Qualcosa non va.

Prelude Graphics.Gloss> :t 100
100 :: Num a => a

Si può leggere 100 è di un tipo qualsiasi a patto che il tipo sia un numero. Ora suona meglio.
La domanda sorge spontanea, quanti tipi che sono numeri esistono ? Qualsiasi tipo che implementi un certo insieme di funzionalità e di comportamenti è un numero.
Non a caso abbiamo i numeri interi, i razionali e i reali anche nella nostra matematica.
La classe Num contiene le funzionalità da implementare per i tipi che ne vogliono essere istanze.
Tanto per curiosare, interroghiamo l’interprete.

Prelude Graphics.Gloss> :i Num
class (Eq a, Show a) => Num a where
  (+) :: a -> a -> a
  (*) :: a -> a -> a
  (-) :: a -> a -> a
  negate :: a -> a
  abs :: a -> a
  signum :: a -> a
  fromInteger :: Integer -> a
  	-- Defined in GHC.Num
instance Num Point -- Defined in Graphics.Gloss.Data.Point
instance Num Integer -- Defined in GHC.Num
instance Num Int -- Defined in GHC.Num
instance Num Float -- Defined in GHC.Float
instance Num Double -- Defined in GHC.Float

Alcune cose erano prevedibili, un numero deve potersi sommare ad un altro, moltiplicare e sottrarre , negare …
Altre sono più tecniche e ci interessano meno.
La lista delle istanze che segue la classe, invece, contiene un particolare interessante.

instance Num Point -- Defined in Graphics.Gloss.Data.Point

La libreria gloss, nel suo modulo Graphics.Gloss.Data.Point ha creato un istanza di Num nuova: l’istanza di Point.
Ora siamo più curiosi.

Prelude Graphics.Gloss> :i Point
type Point = (Float, Float)
  	-- Defined in Graphics.Gloss.Data.Point

Un altro sinonimo di tipo, una coppia di tipi Float. Non ci resta che testarne l’appartenenza alla classe Num

Prelude Graphics.Gloss> (4,5) + (7,1) :: Point
(11.0,6.0)

Ottimo, a parte che ho dovuto annotare l’espressione con :: Point , ma questi sono prezzi da pagare quando si gioca con certe istanze di cui un giorno forse parleremo.

Lascia un commento