380 likes | 1k Vues
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) Ejemplo. Contenido. Graphical User Interface (GUI) Clasificación (High-medium-low)
E N D
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) • Ejemplo Programación Declarativa Avanzada
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 Programación Declarativa Avanzada
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 • 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
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 () Programación Declarativa Avanzada
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?. • 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
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. Programación Declarativa Avanzada
Operaciones Básicas. Entrada getChar::IO Char Recibe: nada. Acción: lee un carácter. Devuelve: el carácter leído. Ejemplo: • Prelude> getChar • a • Prelude> Programación Declarativa Avanzada
Operaciones Básicas. Entrada getLine::IO String Recibe: nada. Acción: lee unalínea ( \n ). Devuelve: un string. • Ejemplo: • Prelude> getLine • Caspita • Prelude> Programación Declarativa Avanzada
Operaciones Básicas. Entrada getContents::IO String Recibe: nada. Acción: lee unalí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. Programación Declarativa Avanzada
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: • import Char • main = interact (map toUpper) • Convierte la entrada del usuario a mayúsculas. Programación Declarativa Avanzada
Operaciones Básicas. Salida putChar::Char -> IO () Primitiva. Recibe: un carácter. Acción: escribe el carácter recibido. Devuelve: nada. Ejemplo: • Main> putChar 'a' • a • Main> Programación Declarativa Avanzada
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: • Main> putStr "puñetas" • puñetas Programación Declarativa Avanzada
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: • Main> putStrLn "puñetas" • Puñetas • Main> Programación Declarativa Avanzada
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. Programación Declarativa Avanzada
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. • readFile "c:/PDA/fentrada" Programación Declarativa Avanzada
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. • 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
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. • appendFile "C:/PDA/CUADRADO" (show [ (x,x*x) | x <- [1,2..100] ] ) Programación Declarativa Avanzada
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 • 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
Operaciones Básicas • Ejemplo de empleo de do • 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
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() Programación Declarativa Avanzada
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 • Where • manejador err = • do putStr (“Se produjo un error” ++ show err ++ “\n”) • muestraFichero’ Programación Declarativa Avanzada
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 Programación Declarativa Avanzada
Graphical User Interface (GUI) • Low-Level. Se obtienen buenos resultados pero son de demasiado bajo nivel. • HOpenGL (sólo gráficos) • TclHaskell • High-Level. Actualmente son experimentales en muchos sentidos, pero se empiezan a obtener buenos resultados. • 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. • FrankTK • Fudgets (veremos ejemplos) • Fruits/wxFruits • Haggis Programación Declarativa Avanzada
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: • Programación perezosa y estructuras infinitas • Funciones de orden superior • Un potente sistema de clases de tipos Programación Declarativa Avanzada
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. Programación Declarativa Avanzada
Graphical User Interface (GUI)FudGets • Algunas Imágenes de lo que se puede lograr: Programación Declarativa Avanzada
Graphical User Interface (GUI)FudGets • Primer Código. ¡Hola Mundo! • import Fudgets main = fudlogue (shellF "Hello" (labelF "Hello, world!")) • import Fudgets main = fudlogue (shellF "Hello" (labelF "Hello, world!" >+< quitButtonF)) Programación Declarativa Avanzada
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]) Programación Declarativa Avanzada
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. Programación Declarativa Avanzada
Graphical User Interface (GUI)WxHaskell • Algunas imágenes que se pueden lograr: Programación Declarativa Avanzada
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" ] Programación Declarativa Avanzada
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 Programación Declarativa Avanzada
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); } } Programación Declarativa Avanzada
Graphical User Interface (GUI)JAVA public class HolaMundoSwing { public static void main(String[] args) { JFrame frame = new JFrame("HolaMundoSwing"); ... frame.pack(); frame.setVisible(true); } } Programación Declarativa Avanzada
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.info-ab.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 OjalaHelsinki University of Technology Programación Declarativa Avanzada
Referencias • Haskell.org (http://haskell.org) • wxHaskell (http://wxhaskell.sourceforge.net/) • FudGets (http://www.md.chalmers.se/Cs/Research/Functional/Fudgets/) Programación Declarativa Avanzada
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 Programación Declarativa Avanzada