Haskell Language Ciao mondo!

Esempio

Un semplice "Hello, World!" il programma in Haskell può essere espresso in modo conciso in una o due righe:

main :: IO ()
main = putStrLn "Hello, World!"

La prima riga è un'annotazione di tipo opzionale, che indica che main è un valore di tipo IO () , che rappresenta un'azione di I / O che "calcola" un valore di tipo () (leggi "unità"; la tupla vuota che non trasmette informazioni) oltre ad eseguire alcuni effetti collaterali sul mondo esterno (qui, stampando una stringa al terminale). Questa annotazione di tipo viene generalmente omessa per main perché è il suo solo tipo possibile.

Metti questo in un file helloworld.hs e compila usando un compilatore Haskell, come GHC:

ghc helloworld.hs

L'esecuzione del file compilato produrrà l'output "Hello, World!" in fase di stampa sullo schermo:

./helloworld
Hello, World!

In alternativa, runhaskell o runghc rendono possibile eseguire il programma in modalità interpretata senza doverlo compilare:

runhaskell helloworld.hs

Il REPL interattivo può anche essere usato al posto della compilazione. Viene fornito con la maggior parte degli ambienti Haskell, come ghci che viene fornito con il compilatore GHC:

ghci> putStrLn "Hello World!"
Hello, World!
ghci> 

In alternativa, caricare gli script in ghci da un file usando load (o :l ):

ghci> :load helloworld

:reload (o :r ) ricarica tutto in ghci:

Prelude> :l helloworld.hs 
[1 of 1] Compiling Main             ( helloworld.hs, interpreted )

<some time later after some edits>

*Main> :r
Ok, modules loaded: Main.

Spiegazione:

Questa prima riga è una firma di tipo, che dichiara il tipo di main :

main :: IO ()

I valori di tipo IO () descrivono le azioni che possono interagire con il mondo esterno.

Poiché Haskell ha un sistema di tipo Hindley-Milner a tutti gli effetti che consente l'inferenza automatica del tipo, le firme dei tipi sono tecnicamente facoltative: se si omette semplicemente il main :: IO () , il compilatore sarà in grado di dedurre il tipo da solo analizzando la definizione di main . Tuttavia, è molto considerato uno stile negativo non scrivere le firme dei tipi per le definizioni di livello superiore. I motivi includono:

  • Digitare le firme in Haskell è una documentazione molto utile perché il sistema dei tipi è così espressivo che spesso si può vedere che tipo di cosa è utile per una funzione semplicemente osservando il suo tipo. Questa "documentazione" può essere facilmente accessibile con strumenti come GHCi. E a differenza della normale documentazione, il controllo del tipo del compilatore farà in modo che corrisponda effettivamente alla definizione della funzione!

  • Le firme dei tipi mantengono i bug locali . Se si commette un errore in una definizione senza fornire la propria firma del tipo, il compilatore potrebbe non segnalare immediatamente un errore, ma invece dedurre semplicemente un tipo non sensato per esso, con il quale in realtà digita i caratteri. È quindi possibile ottenere un messaggio di errore criptico quando si utilizza tale valore. Con una firma, il compilatore è molto bravo a individuare gli errori nel punto in cui accadono.

Questa seconda riga fa il lavoro reale:

main = putStrLn "Hello, World!"

Se vieni da una lingua imperativa, potrebbe essere utile notare che questa definizione può anche essere scritta come:

main = do {
   putStrLn "Hello, World!" ;
   return ()
   }

O in modo equivalente (Haskell ha un parsing basato sul layout, ma attenzione a mescolare in modo incoerente tab e spazi che confonderanno questo meccanismo):

main = do
    putStrLn "Hello, World!"
    return ()

Ogni riga in un blocco do rappresenta un calcolo monodico (qui, I / O), in modo che l'intero blocco do rappresenti l'azione complessiva composta da questi sottomasi combinandoli in un modo specifico per la monade data (per I / O questo significa solo eseguirli uno dopo l'altro).

La sintassi do è a sua volta uno zucchero sintattico per le monadi, come IO qui, e return è un'azione no-op che produce il suo argomento senza eseguire effetti collaterali o calcoli aggiuntivi che potrebbero far parte di una particolare definizione di monade.

Quanto sopra è lo stesso della definizione di main = putStrLn "Hello, World!" , perché il valore putStrLn "Hello, World!" ha già il tipo IO () . Visto come una "dichiarazione", putStrLn "Hello, World!" può essere visto come un programma completo, e basta semplicemente definire main per riferirsi a questo programma.

Puoi cercare la firma di putStrLn online :

putStrLn :: String -> IO ()
-- thus,
putStrLn (v :: String) :: IO ()

putStrLn è una funzione che accetta una stringa come argomento e genera un'azione di I / O (ovvero un valore che rappresenta un programma che il runtime può eseguire). Il runtime esegue sempre l'azione denominata main , quindi è sufficiente definirla come uguale a putStrLn "Hello, World!" .