6 jul 2009

Mónadas (Haskell) Ejemplos

Las mónadas son parte de la teoría de las categorias, tema de estudio en álgebra moderna/abstracta. En un curso de álgebra moderna 3 se suelen estudiar. ¿Pero que tiene que ver con Haskell?. Las monádas permiten modelar acciones de entrada y salida preservando la caraterística principal de Haskell: "todo es una función" . (en realidad ya no sé si esto sea cierto, lo que e un hecho es que da un fundamento matemático a las acciones de E/S que claramente no se comportan como funciones)

Considere la "función" recibeEntero, de un lenguaje imperativo, que toma de la entrada estándar un entero. ¿cual es el resultado de

recibeEntero - recibeEntero

???

Uno esperaría que fuera cero pero obviamente no!!! ya que en la primera ejecución de recibeEntero se pudo obtener un valor de 4 y en la segunda ejecución un 2 y 4 -2 = 2 . Por este tipo de cosas es que era algo espinoso modelar acciones de E/S en lenguajes funcionales puros com Haskell. Lo bueno es que alguien se le ocurrió usar monádas para introducir este tipo de cosas en lenguajes funcionales. No explicaré la teoría de las mónadas ni el porque arreglan el asunto espinoso... si no que daré solamente ejemplos de como se usan las mónadas de E/S. En algún momento escribiré muchos más ejemplos. Sin embargo si alguien quiere estudiar mónadas en sus vacaciones (o ratos libres como yo) puede consultar el tutorial The Haskell Programmer's Guide to the IO Monad-- don't panic .Disponible aqui.

Acciones de entrada y salida.

Para obtener un String de la entrada estándar usamos getLine, para "sacar" una cadena en la salida estándar usamos putStr. Ejemplos



saludo = putStr "Hola mundo"
ei = getLine



Si queremos hacer una secuencia de estas acciones tenemos que usar la sentencia do. Ejemplos:



putsl =
do
putStr "hola amigos\n"
putStr "como estan ?\n"



Podemos hacer "asignaciones" haciendo uso de "<-". Ejemplos

:

putsl =
do
linea <- getLine
putStr linea


donde <- juega el papel de (:= ). Es importante hacer notar que no se esta haciendo una asignación como en un lenguaje imperativo, si no una definición. Aqui linea se nombra o define como lo que se leyó de la entrada estándar.

Podemos usar recursión:


printN n cadena =
.....if n <= 1 then
........putStr (cadena++"\n")
.....else
.........do
..........putStr (cadena++"\n")
..........printN (n-1) cadena




Esta última función imprime n veces una cadena. Si se quiere imprimir por ejemplo 5 veces hola uno ejecutaría :

 Main> printN 5 "hola"


y la salida correspondiente sería:


hola
hola
hola
hola
hola



Hasta ahora solo se ha leido e imprimido cadenas (Strings) pero también es posible usar enteros. Para leer enteros se lee primero cadenas que se parsean a enteros de la siguiente manera:



.
.
.
line <- getLine --leemos de la entrada estándar
. . --hacemos otras cosas .
x <- return (read line ::Int) -- x el resutlado de parsear line (un String) a un entero



return juega un papel muy parecido al que todo programador conoce.
Ejemplos de funciones que usan monádas de entrada y salida:



{-
Lee una cadena la parsea a entero y regresa ese entero mas uno
-}

leeEntero =
....do
......putStr "Introduce un n"
......line <- getLine
......x <- return (read line ::Int)
......return (x +1)

{- Función auxiliar -}

suman n
....| n==0 = 0
....| otherwise = n + (suman (n-1))

{- Suma los primeros n numeros naturales, la n es introuducida por el usuario -}

sumaN =
....do
......putStr "Hasta que numero quieres sumar?"
......line <-getLine
......n <- return (read line ::Int)
......let suma = suman n
......return suma

{- Regresa true en caso de que la palabra introducida sea un palindroma -}
esPalin =
....do
......putStr "Introduce la palabra a probar: "
......word <- getLine
......let es = (reverse word ) == word
......return es



Todas estas funciones fueron probadas con GHCi, en hugs también funcionan, pero el resultado por algún motivo no se muestra.... Se usan los (....) para obtener la identación adecuada en blogger del código. Si alguien quiere probar el código lo puede descargar de aqui.

Con las mónadas podemos definir un while, leer archivos, y muchas cosas más .Esto es sólo una introudcción.

No hay comentarios:

ga