Haskell Hero

Haskell Hero es un manual interactivo del lenguaje Haskell para principiantes.

Entrada y salida I

¿Por qué operaciones de entrada y salida?

Hasta ahora hemos aprendido como evaluar expresiones y como definir funciones. Sin embargo, muchas veces vamos a querer que nuestros programas:

  • lean entradas de usuarios
  • lean entradas de archivos
  • informen a usuarios sobre el progreso del cálculo
  • ...

Para estas operaciones usamos operaciones de entrada y salida, normalmente llamadas operaciones IO (de palabras inglesas input/output) o solamente IO.

Estas operaciones las llamamos a menudo acciones.

Operaciones básicas

Si dejamos Hugs evaluar la expresión "bbbccc", Hugs indica que se trata de una expresión y la devuelve sin cambios. Sin embargo, si le dejamos evaluar la expresión

putStr "bbbccc"
Hugs indica que putStr es una acción y la realiza. La acción putStr toma una cadena y la imprime. Realizando la acción no se devuelve un resultado. Lo que se imprime es solamente un efecto de la acción putStr.

Además, la función putStr puede imprimir también caracteres especiales. Por ejemplo la realización de la acción

putStr "aaa\nbbb\nccc"
Se hace de manera siguiente: \n se sustituye por una línea nueva y se imprime
aaa
bbb
ccc

Podemos mencionar otras acciones IO sencillas:

  • putStrLn hace lo mismo que putStr pero después de imprimir el parámetro añade una nueva línea
  • getLine lee la entrada del usuario y después devuelve su valor
  • readFile lee el contenido de un archivo

Juntamos acciones IO

En la mayoría de los casos no queremos realizar solo una acción IO pero queremos juntar más de ellas. Por ejemplo queremos leer un valor de un usuario, evaluarlo e imprimirlo para el usuario como el resultado.

Las acciones IO se juntan con la construcción do. Por ejemplo la función nularia que imprime cadenas "abc", "def" y "ghi" se define de manera siguiente:

imprime = do putStrLn "abc"
             putStrLn "def"
             putStrLn "ghi"
Cuidado con la sangría! Las acciones que se deben realizar en el bloqueo hay que sangrarlas del mismo modo. Hay también una variante de la notación de una sola línea:
imprime = do {putStrLn "abc"; putStrLn "def"; putStrLn "ghi"}

Además de las acciones también podemos "guardar" el resultado de una acción IO en el bloqueo, ligarlo con un valor y después trabajar con la referencia al valor.

valorReferencia <- accionIO

"Guardar" está entre comillas porque no se trata de guardar datos en un lugar de la memoria. Vamos a explicarlo más tarde.

Podemos guardar el resultado intermedio solo en el bloqueo. Si lo usamos fuera del bloqueo, la compilación termina con un error.

Ejemplo

Definid la función nularia main :: IO () que lee una cadena del usuario, imprime Has escrito: y después imprime la cadena recibida.


Escribimos la definición de la misma manera como las instrucciones.

  1. Leemos la entrada del usuario y vamos a guardarla.
  2. Imprimimos la cadena "Has escrito: ".
  3. Imprimimos la cadena recibida que hemos guardado al principio.
main = do s <- getLine
          putStr "Has escrito: "
          putStr s