Entrada/Salida en el lenguaje funcional Haskell Carlos Caballero González

Download Report

Transcript Entrada/Salida en el lenguaje funcional Haskell Carlos Caballero González

Entrada/Salida en el
lenguaje funcional
Haskell
Carlos Caballero González
Contenido



El problema de la E/S en Haskell
El tipo IO
Operaciones Básicas


Ejemplos
El tipo IOError (Capturar excepciones)

26/05/2016
Ejemplo
Programación Declarativa Avanzada
2
Contenido

Graphical User Interface (GUI)

Clasificación (High-medium-low)





Ejemplos FudGets
Ejemplos WxHaskell
Comparación de Código con JAVA
Referencias
Conclusión Personal
26/05/2016
Programación Declarativa Avanzada
3
El problema de la E/S en
Haskell

Haskell es un lenguaje funcional puro la integración
de las operaciones de entrada y salida podría hacer
perder la transparencia referencial del lenguaje

Supongamos que queremos leer un Entero desde el
teclado



26/05/2016
leerEntero :: Entero
Para todo n Entero se cumple que n + n = 2n
Pero la función leerEntero no cumpliría esta condición
pues: leerEntero + leerEntero != 2* leerEntero
Programación Declarativa Avanzada
4
El tipo IO



La solución que aporta Haskell es tener un
tipo específico para realizar las operaciones
de Entrada Salida, este tipo es IO()
Es una mónada
Estructura de dato que encapsula una acción
putChar :: IO Char
getChar :: Char -> IO ()
26/05/2016
Programación Declarativa Avanzada
5
El tipo IO



El tipo IO a indica una acción de Entrada/Salida que
devuelve un valor de tipo a
Hemos puesto IO a.
¿Por qué no ponemos solamente IO?.


26/05/2016
Porque toda acción debe devolver como resultado un dato
concreto, y este dato también tendrá un tipo.
Cuando es un dato sin valor útil, su tipo será vacío (). Por
lo tanto, además de IO (que representa una acción),
aparecerá el tipo de dato concreto que devuelve dicha
acción.
Programación Declarativa Avanzada
6
Operaciones Básicas.

Todas las funciones que se describen a continuación se
encuentran en el módulo Prelude. No es necesario importar
ninguna librería para poder utilizarlas.

Funciones de Entrada.
 Son funciones que obtienen los datos del puerto de entrada
estándar, normalmente el teclado del terminal de usuario.

Funciones de Salida.
 Funciones que escriben los datos en el puerto de salida
estándar, normalmente el monitor del terminal de usuario.
26/05/2016
Programación Declarativa Avanzada
7
Operaciones Básicas. Entrada
getChar::IO Char
Recibe: nada.
Acción: lee un carácter.
Devuelve: el carácter leído.
Ejemplo:



26/05/2016
Prelude> getChar
a
Prelude>
Programación Declarativa Avanzada
8
Operaciones Básicas. Entrada
getLine::IO String
Recibe: nada.
Acción: lee una línea ( \n ).
Devuelve: un string.
 Ejemplo:



26/05/2016
Prelude> getLine
Caspita
Prelude>
Programación Declarativa Avanzada
9
Operaciones Básicas. Entrada
getContents::IO String
Recibe: nada.
Acción: lee una línea ( \n ).
Devuelve: un string.
Hace lo mismo que getLine pero utilizando
evaluación perezosa. Coge los caracteres
uno a uno según se van necesitando.
26/05/2016
Programación Declarativa Avanzada
10
Operaciones Básicas. Entrada

interact:: ( String -> String ) -> IO ()

Se basa en la primitiva getContents para leer y en putStr para
escribir.
Recibe: una función de tipo String -> String.
Acción: lee un String del puerto de entrada, lo pasa a la función y
el String resultado lo escribe en el puerto de salida.
Devuelve: nada.
Ejemplo:







26/05/2016
import Char
main = interact (map toUpper)
Convierte la entrada del usuario a mayúsculas.
Programación Declarativa Avanzada
11
Operaciones Básicas. Salida
putChar::Char -> IO ()
Primitiva.
Recibe: un carácter.
Acción: escribe el carácter recibido.
Devuelve: nada.
Ejemplo:



26/05/2016
Main> putChar 'a'
a
Main>
Programación Declarativa Avanzada
12
Operaciones Básicas. Salida
putStr::String -> IO ()
Se basa en la primitiva putChar.
Recibe: un String.
Acción: escribe el String recibido. Utiliza putChar para
escribir los caracteres de uno en uno.
Devuelve: nada.
Ejemplo:


26/05/2016
Main> putStr "puñetas"
puñetas
Programación Declarativa Avanzada
13
Operaciones Básicas. Salida
putStrLn::String -> IO ()
Recibe: un String.
Acción: escribe el String recibido. Utiliza putStr,
añadiendo un carácter de “nueva línea”
Devuelve: nada.
Ejemplo:
26/05/2016


Main> putStrLn "puñetas"
Puñetas

Main>
Programación Declarativa Avanzada
14
Operaciones Básicas.
Ficheros

Funciones que actúan sobre ficheros de caracteres.



type
FilePath
=
String
Una forma de nombrar los ficheros. Es un String
que contiene la ruta del fichero.
Internamente utiliza algún método específico de
implementación para convertir cadenas en
identificadores de fichero válidos para el sistema.
26/05/2016
Programación Declarativa Avanzada
15
Operaciones Básicas.
Ficheros

readFile::FilePath -> IO String

Recibe: un nombre de fichero.
Acción: lee el fichero indicado.
Devuelve: un String con el contenido del fichero.
El fichero se lee según se necesita, de forma
“perezosa”. En este sentido funciona igual que la
función getContents.
Ejemplo.





26/05/2016
readFile "c:/PDA/fentrada"
Programación Declarativa Avanzada
16
Operaciones Básicas.
Ficheros

writeFile::FilePath -> String -> IO ()

Recibe: un nombre de fichero y un String.
Acción: escribe el String recibido como segundo argumento en el
fichero indicado. Presupone que existe y borra su contenido
antes de escribir.
Devuelve: nada.
Para escribir un valor que no sea de tipo String, debe convertirse
previamente con la función show.
Ejemplo.






26/05/2016
writeFile "C:/PDA/CUADRADO" (show [ (x,x*x) | x <- [1,2..100] ]
Escribe en el fichero cuadrado el par formado por los 100 primeros
números y sus cuadrados.
Programación Declarativa Avanzada
17
Operaciones Básicas.
Ficheros

appendFile::FilePath -> String -> IO ()

Lo mismo que writeFile pero añade el String
al final del fichero, manteniendo el contenido
anterior.
Ejemplo.


26/05/2016
appendFile "C:/PDA/CUADRADO" (show [ (x,x*x) | x <[1,2..100] ] )
Programación Declarativa Avanzada
18
Operaciones Básicas

return::a-> IO a

Se emplea para convertir un valor en una acción, puede ser
interpretada como la identidad.




Ejemplo:
return x
x
do




26/05/2016
Las acciones se ejecutan secuencialmente
El ámbito de una variable introducida por <- son las acciones
posteriores hasta el final de la expresión do
El tipo de la expresión do es el tipo de la última acción
La regla del sangrado de Haskell se aplica tras la palabra do, por
lo que todas las acciones de su ámbito deben estar en la misma
columna
Programación Declarativa Avanzada
19
Operaciones Básicas

Ejemplo de empleo de do








26/05/2016
miAcción :: IO()
miAcción = do putStr “Dame un texto: ”
xs <- getLine
putStr “En mayúsuclas es: “
putStr (map toUpper xs)
Main> miAcción
Dame un texto: puñetas
En mayúsuclas es: PUÑETAS
Programación Declarativa Avanzada
20
Tipo IOError ()

Ejemplo:



muestraFichero :: IO()
muestraFichero = do putStr “Introduce nombre del fichero: ”
nombre <- getLine
contenido <- readFile nombre
putStr contenido

¡¿Qué sucede si el fichero no existe?!



Como cualquier lenguaje de programación Haskell
debe proporcionarnos mecanismos para controlar
los posibles errores, en el caso de Entrada/Salida
Haskell proporciona el tipo IOError()
26/05/2016
Programación Declarativa Avanzada
21
El tipo IOError()

Las excepciones pueden ser tratadas mediante la
función catch




Catch :: IO a -> (IOError -> IO a) -> IO a
Primer Argumento: La acción a realizar
Segundo Argumento: La acción en caso de excepción
Ejemplo:


muestraFichero’ :: IO()
muestraFichero’ = muestraFichero ‘catch’ manejador

26/05/2016
Where
 manejador err =

do putStr (“Se produjo un error” ++ show err ++ “\n”)

muestraFichero’
Programación Declarativa Avanzada
22
Graphical User Interface (GUI)




Existe un gran número de bibliotecas para generar
GUI en Haskell.
Desgraciadamente no hay ningún estándar (todas
tienen ventajas y deficiencias respecto a otras)
Son independientes al núcleo de Haskell (debido a
que no existe el estándar)
Normalmente estas bibliotecas se han clasificado
como low-level, medium-level y High-level
26/05/2016
Programación Declarativa Avanzada
23
Graphical User Interface (GUI)

Low-Level. Se obtienen buenos resultados pero son de demasiado bajo
nivel.



High-Level. Actualmente son experimentales en muchos sentidos, pero
se empiezan a obtener buenos resultados.





HOpenGL (sólo gráficos)
TclHaskell
wxHaskell (veremos ejemplos)
Gtk2HS
HGL (Sólo gráficos)
Object I/O
Medium-level. Como todo en muchos problemas hay que llegar a un
consenso.




26/05/2016
FrankTK
Fudgets (veremos ejemplos)
Fruits/wxFruits
Haggis
Programación Declarativa Avanzada
24
Graphical User Interface (GUI)

¿Por qué elegir trabajar con Haskell + GUI ?



El programador se encuentra igual de cómodo
trabajando en el desarrollo de GUI’s con Haskell que
con cualquier otro lenguaje
TODAS las bibliotecas tienen un API bastante
aclaratorio y fácil de comprender (como JAVA)
Se poseen características propias de un lenguaje
declarativo que no se posee en otros lenguajes como:



26/05/2016
Programación perezosa y estructuras infinitas
Funciones de orden superior
Un potente sistema de clases de tipos
Programación Declarativa Avanzada
25
Graphical User Interface (GUI)
FudGets



FudGets es una biblioteca de GUI’s para el
lenguaje funcional Haskell.
El trabajo principal de esta biblioteca fue
desarrollada durante 1991-1996 aunque aún
se esta manteniendo la biblioteca.
Fue desarrollada por Thomas Hallgren y
Magnus Carlsson.
26/05/2016
Programación Declarativa Avanzada
26
Graphical User Interface (GUI)
FudGets

Algunas Imágenes de lo que se puede lograr:
26/05/2016
Programación Declarativa Avanzada
27
Graphical User Interface (GUI)
FudGets

Primer Código. ¡Hola Mundo!
26/05/2016

import Fudgets main = fudlogue (shellF "Hello" (labelF "Hello,
world!"))

import Fudgets main = fudlogue (shellF "Hello" (labelF "Hello,
world!" >+< quitButtonF))
Programación Declarativa Avanzada
28
Graphical User Interface (GUI)
FudGets
import Fudgets
main = fudlogue (shellF "Pocket Calculator" calcF)
calcF = intDispF >==< mapstateF calc [0] >==< buttonsF
data Buttons = Plus | Minus | Times | Div | Enter | Digit Int deriving (Eq)
buttonsF = placerF (matrixP 4) (
listF [d 7, d 8, d 9,op Div,
d 4, d 5, d 6,op Times,
d 1, d 2, d 3,op Minus,
hole,d 0,ent, op Plus])
where
d n = (Digit n,buttonF (show n))
ent = op Enter hole = (Enter,holeF)
op o = (o,buttonF (opLabel o))
where opLabel Plus = "+"
opLabel Minus = "-“
opLabel Times = "*“
opLabel Div = "/“
opLabel Enter = "Ent"
calc (n:s) (Digit d,_) = new (n*10+d) s
calc s (Enter,_) = (0:s,[])
calc (y:x:s) (Plus,_) = new (x+y) s
calc (y:x:s) (Minus,_) = new (x-y) s
calc (y:x:s) (Times,_) = new (x*y) s
calc (y:x:s) (Div,_) = new (x `div` y) s
calc s _ = (s,[]) new n s = (n:s,[n])
26/05/2016
Programación Declarativa Avanzada
29
Graphical User Interface (GUI)
WxHaskell



wxHaskell es una biblioteca de GUI’s para el
lenguaje Haskell
Comenzó a desarrollarse en 1992
Se encuentra entre los 25 proyectos más
activos de código abierto.
26/05/2016
Programación Declarativa Avanzada
30
Graphical User Interface (GUI)
WxHaskell

Algunas imágenes que se pueden lograr:
26/05/2016
Programación Declarativa Avanzada
31
Graphical User Interface (GUI)
WxHaskell
import Graphics.UI.WX
main :: IO ()
main = start hello
hello :: IO ()
hello = do
f <- frame [text := "Hello world!", clientSize := sz 300 200]
file <- menuPane [text := "&File"]
quit <- menuQuit file [help := "Quit the demo", on command := close f]
hlp <- menuHelp []
about <- menuAbout hlp [help := "About wxHaskell"]
status <- statusField [text := "Welcome to wxHaskell"]
set f [ statusBar := [status] , menuBar := [file,hlp] ,on (menu about) :=
infoDialog f "About wxHaskell" "This is a wxHaskell demo" ]
26/05/2016
Programación Declarativa Avanzada
32
Graphical User Interface (GUI)
WxHaskell
import Graphics.UI.WX
import Graphics.UI.WXCore
main = start $
do f <- frame [text := "Custom color box controls"]
c <- colorBox f [boxcolor := red]
set f [layout := floatCenter $ widget c ,clientSize := sz 280 100]
type ColorBox a = Window (CColorBox a)
data CColorBox a = CColorBox
colorBox :: Window a -> [Prop (ColorBox ())] -> IO (ColorBox ())
colorBox parent props =
do let defaults = [clientSize := sz 20 20, border := BorderStatic]
cboxprops = castProps cast props
w <- window parent (defaults ++ cboxprops)
let cbox = cast w
set cbox [on click := selectColor cbox]
return cbox
where
selectColor cbox pt
= do c <- get cbox boxcolor
mbc <- colorDialog cbox c
case mbc of
Just c -> set cbox [boxcolor := c]
Nothing -> return ()
cast :: Window a -> ColorBox ()
cast = objectCast
boxcolor :: Attr (ColorBox a) Color
boxcolor = newAttr "boxcolor" getter setter
where
getter cbox = get cbox bgcolor
setter cbox clr = do set cbox [bgcolor := clr] refresh cbox
26/05/2016
Programación Declarativa Avanzada
33
Graphical User Interface (GUI)
JAVA

El simple “Hola Mundo” de 3 lineas en cualquiera de las bibliotecas de GUI’s de JAVA se
convierte en una labor más tediosa
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class HolaMundoSwing {
public static void main(String[] args) {
JFrame frame = new JFrame("HolaMundoSwing");
final JLabel label = new JLabel("Hola Mundo"); frame.getContentPane().add(label);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.addWindowListener(new
java.awt.event.WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
} );
frame.pack();
frame.setVisible(true);
}
}
26/05/2016
Programación Declarativa Avanzada
34
Graphical User Interface (GUI)
JAVA
public class HolaMundoSwing {
public static void main(String[] args) {
JFrame frame = new JFrame("HolaMundoSwing");
...
frame.pack();
frame.setVisible(true);
}
}
26/05/2016
Programación Declarativa Avanzada
35
Referencias





Razonando con Haskell. Un curso sobre programación funcional.
Blas C. Ruiz, Fco. Gutiérrez, Pablo Guerrero, José E. Gallardo
(2004)
A Gentle introduction to Haskell.
P. Hudak, J. Fasel (1999)
Entrada / Salida en Haskell
(http://www.infoab.uclm.es/asignaturas/42630/BuzAPD/Trabajos/IOHaskell.doc)
Introducción al lenguaje Haskell.
(http://lsi.uniovi.es/~labra/FTP/IntHaskell98.pdf)
Jose E. Labra G.
(1998)
IO in Haskell. Using stream- and monad-IO in Haskell.
Oskar Ojala Helsinki University of Technology
26/05/2016
Programación Declarativa Avanzada
36
Referencias



Haskell.org (http://haskell.org)
wxHaskell (http://wxhaskell.sourceforge.net/)
FudGets
(http://www.md.chalmers.se/Cs/Research/Fu
nctional/Fudgets/)
26/05/2016
Programación Declarativa Avanzada
37
Conclusión Personal




En Haskell se puede desarrollar exactamente lo mismo que se
puede desarrollar en cualquier lenguaje actual con capacidad de
desarrollo de GUI’s
El desarrollo de las GUI’s en Haskell son incluso más simples
que en cualquier otro lenguaje
Se dispone de las características de un lenguaje declarativo
(Programación perezosa y estructuras infinitas, funciones de
orden Superior, potente sistema de clases de tipos)
Es una verdadera desgracia que no se haya equipado de un
estándar para poder realizar GUI’s en Haskell potenciaría de una
gran manera el desarrollo de las mismas, no dejandolas de las
manos de particulares
26/05/2016
Programación Declarativa Avanzada
38