Haskell Language ¡Hola Mundo!


Ejemplo

Un básico "¡Hola mundo!" El programa en Haskell se puede expresar de manera concisa en solo una o dos líneas:

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

La primera línea es una anotación de tipo opcional, que indica que main es un valor de tipo IO () , que representa una acción de E / S que "calcula" un valor de tipo () (lea "unidad"; la tupla vacía no transmite información) además de realizar algunos efectos secundarios en el mundo exterior (aquí, imprimir una cadena en el terminal). Esta anotación de tipo se suele omitir para main porque es su único tipo posible.

Coloca esto en un archivo helloworld.hs y compílalo usando un compilador de Haskell, como GHC:

ghc helloworld.hs

La ejecución del archivo compilado dará como resultado la salida "Hello, World!" siendo impreso a la pantalla:

./helloworld
Hello, World!

Alternativamente, runhaskell o runghc hacen posible ejecutar el programa en modo interpretado sin tener que compilarlo:

runhaskell helloworld.hs

El REPL interactivo también se puede utilizar en lugar de compilar. Se entrega con la mayoría de los entornos de Haskell, como ghci que viene con el compilador de GHC:

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

Alternativamente, cargue scripts en ghci desde un archivo usando load (o :l ):

ghci> :load helloworld

:reload (o :r ) :reload todo en 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.

Explicación:

Esta primera línea es una firma de tipo, declarando el tipo de main :

main :: IO ()

Los valores de tipo IO () describen acciones que pueden interactuar con el mundo exterior.

Debido a que Haskell tiene un sistema de tipo Hindley-Milner completo que permite la inferencia de tipos automática, las firmas de tipos son técnicamente opcionales: si simplemente omite main :: IO () , el compilador podrá inferir el tipo por sí mismo. Analizando la definición de main . Sin embargo, se considera un estilo muy malo no escribir firmas de tipo para definiciones de nivel superior. Las razones incluyen:

  • Las firmas de tipos en Haskell son una pieza de documentación muy útil porque el sistema de tipos es tan expresivo que a menudo se puede ver qué tipo de cosa es buena para una función simplemente observando su tipo. Se puede acceder cómodamente a esta "documentación" con herramientas como GHCi. ¡Y a diferencia de la documentación normal, el verificador de tipos del compilador se asegurará de que realmente coincida con la definición de la función!

  • Las firmas de tipos mantienen los errores locales . Si comete un error en una definición sin proporcionar su tipo de firma, es posible que el compilador no informe un error de inmediato, sino que simplemente infiera un tipo sin sentido para el mismo, con el que realmente verifica. Luego puede obtener un mensaje de error críptico cuando use ese valor. Con una firma, el compilador es muy bueno para detectar errores justo donde ocurren.

Esta segunda línea hace el trabajo real:

main = putStrLn "Hello, World!"

Si proviene de un lenguaje imperativo, puede ser útil tener en cuenta que esta definición también se puede escribir como:

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

O de manera equivalente (Haskell tiene un análisis basado en el diseño; pero tenga cuidado al mezclar las pestañas y los espacios de manera inconsistente, lo que confundirá este mecanismo):

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

Cada línea en un bloque do representa algún cálculo monádico (aquí, E / S), de modo que todo el bloque do representa la acción general que comprende estos subpasos combinándolos de una manera específica a la mónada dada (para I / O esto significa simplemente ejecutándolos uno tras otro).

La sintaxis do es en sí misma un azúcar sintáctico para las mónadas, como IO aquí, y el return es una acción no operativa que produce su argumento sin realizar efectos secundarios ni cálculos adicionales que puedan formar parte de una definición de mónada particular.

Lo anterior es lo mismo que definir main = putStrLn "Hello, World!" , porque el valor putStrLn "Hello, World!" Ya tiene el tipo IO () . Visto como una "declaración", putStrLn "Hello, World!" puede verse como un programa completo, y usted simplemente define main para referirse a este programa.

Puedes consultar la firma de putStrLn línea :

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

putStrLn es una función que toma una cadena como argumento y genera una acción de E / S (es decir, un valor que representa un programa que el tiempo de ejecución puede ejecutar). El tiempo de ejecución siempre ejecuta la acción denominada main , por lo que simplemente debemos definirla como igual a putStrLn "Hello, World!" .