antonio's Blogs de amigos

Vistaso general de la libreria uu-parsinglib, version 2.7.1.1

September 17, 2011 por Carlos Gomez   Comentarios (0)

, ,

Como algunos ya saben, nos estamos volviendo a reunir los de la comunidad haskell. Y en esta ultima reunion (17 de septiembre), hice una pequeña presentacion sobre la libreria uu-parsinglib (version 2.7.1.1). 

Bueno, les comparto la presentacion (*.pdf) y el codigo del proyecto utilizado en la presentacion.

Presentacion

Codigo del proyecto

Por cierto, pueden descargar la libreria uu-parsinglib de hackage, de la siguiente direccion: http://hackage.haskell.org/package/uu-parsinglib

Saludos, Carlos Gomez

 

Utrecht Summer School - Applied Functional Programming

September 11, 2010 por Carlos Gomez   Comentarios (0)

, , ,

En esta oportunidad quiero compartirles algo de la experiencia que he tenido en el curso de verano Applied Functional Programming de la Universidad de Utrecht - Holanda, realizada en fechas 16–27 de Agosto.

El viaje mas largo

Llegar a Utrecht-Holanda ha sido uno de los viajes mas largos que he tenido hasta ahora; Sali de mi casa un Jueves 12 y llegue a Utrecht(Houten) el Sabado por la noche (20:00).

En total han sido 10 horas de viaje en flota de Cochabamba a Santa Cruz, y luego 12 horas de viaje en avion de Santa Cruz a Madrid-Espania, de ahi otras 2 horas de viaje por avion de Madrid-Espania a Amsterdam-Holanda, y de ahi otras 2 horas mas de viaje en tren de Amsterdam-Holanda a Houten-Holanda (deberia haber sido solo 45 minutos, pero se extendio a 2 horas porque nos perdimos en la gigante estacion de trenes de Holanda), y para terminar una caminata de 20 minutos con direccion a la casa de Doaitse Swierstra.

El viaje de retorno ha sido similar, solo que nos ahorramos 30 minutos de viaje en tren (desde Utrecht a Amsterdam) gracias a los hijos de Pits porque nos llevaron en su automovil hasta el aeropuerto de Schipol-Amsterdam.

Un lugar hermoso, Utrecht-Holanda

Utrecht es un lugar muy hermoso, comensando desde sus rios que atraviesan gran parte de Utrecht por los cuales se puede pasear en canoa y barcos, su variedad de arbustos y plantas, todas vestidas de verde, sus casas al estilo antiguo (similar a Sucre-Bolivia) (antiguas pero llenas de tecnologia actual adentro de las casas), su gente muy amigable, un ambiente tranquilo.

Algo que me sorprendio fue que el sol se perdia recien a las 21 horas, era sorprendente ver parte de la noche aun con sol. Lo que no pude saber es la hora en el el sol salia, ya que las veces que me levante temprano, el sol ya estaba arriba.

Otra cosa que me sorprendio es que la bicicleta es un medio comun de transporte para la mayoria de la gente, y apesar de la existencia de buses y taxis, habia un inmensa fila de bicis estacionadas en el parqueo. A comentario personal, me hicieron dar muchas ganas de manejar un bici en Bolivia.

El lugar de hospedaje

Me he hospedado en el edificio de Kruisstraat/Parnassos, un lugar muy hermoso que se encuentra en Utrecht Central, a 45 minutos a pie o 20 minutos en bici de la universidad de Utrecht.

En mi cuarto tenia una cama donde dormir (que en seria era muy comoda), un armario para la ropa y otro para mis cosas, una mesa mediana, una silla (como las de laboratorio, osea con ruedas) y otra silla de descanzar, una lampara y otros furnitures de mesa y tambien una conexion a internet que venia con su hub y cables.

En el piso tambien habia una cosina completa que no la use mucho y baños.

La Universidad de Utrecht

Para empesar la Universidad de Utrecht es gigante, no llegue a conocer todo, solo conoci algunas partes de ella.

Conoci la parte de la Facultad de Ciencias Naturales, donde se encuentra la carrera de Informatica, y tambien parte del edificio de Informatica.

Pase clases en el edificio de Minaert-Uithof, y si no me equivoco es donde esta la central de la Facultad de Ciencias Naturales; Sus ambientes son como para 50 estudiantes, equipadas con data display y computador, doble pizarra y asientos y mesas comodas para los estudiantes y tomacorrientes en cada mesa. Y sin exagerar, tenian cortinas manuales y automaticas contra el sol (cuando el sol entraba por una de las ventanas estas se cerraban automaticamente). Tambien nos asignaron cuentas para tener acceso a la web.

Los laboratorios tambien eran muy comodos, tenian instalados Windows y Linux Red Hat, con monitores medianos y sillas con ruedas y muy comodas, tambien habia pizarra doble y una computadora al lado del pizaron. Por los pasillos del edificio habian computadoras (similares a las computadoras de la bibliteca de la [Facultad de Ciencias y Tecnologia] de [San Simon]), por las cuales se podia navegar por internet.

La universidad tambien tenia varios lugares donde guardar las bicicletas, y otros lugares donde pasar el tiempo como ser jardines, pequenios lugares de recreacion (asi como en la [San Simon]) y lugares donde servirse algo de comer. En especial he conocido dos lugares de la universidad para comer, no nocozco sus nombres, pero servian bien, mejor dicho te podias servir lo que querias y eso era bueno. Tenian una gran variadad de cosar para servirse: panes, refrescos, galletas, ensaladas, bebidas, sopas, papas, etc. Y eso que no logre ver todo.

Los amigos del curso y docentes

Asistimos al curso 31 estudiantes, tuvimos dos profesores principales (Doaitse Swierstra y Andres Loeh), varios auxiliares que estaban en la maestria y doctorado y tambien otros expositores como ser Atze Dijkstra, Don Steward y Duncan Coutts.

Mis compañeros venian de distintas areas, algunos matematicos, otros de programacion web, unos con nada de conocimientos sobre programacion funcional, otros con conocimeintos previos de funcional, y otros algo expertos en el area de programacion funcional. Tambien habian de distintos niveles de carrera y edades, unos con doctorado, otros en 4to semestre de universidad, y la mayoria con un nivel de licenciatura o egreso. Las edaddes creo que variaban entre 20 y 40 anios.

Todos eramos relativamente amigables, sin embargo no llegue a conocer a todos ellos, pero tuve amigos muy cercanos.

Estrucura general de los dias

Normalmente me levantaba entre las 7 y 7:30 am, me daba un aseo general, me preparaba mi desayuno, y luego agarraba la bici o el bus o las patas para llegar a las 9:00am para la lectura de la maniana, esta lectura era desde las 9 hasta las 10:30–11:00 y luego pasabamos al laboratorio hasta las 12:30 y si queriamos podiamos seguir en el laboratorio o ir a comer, yo normalmente solia ir a comer y pasar el tiempo hasta las 14:00, que era el tiempo para la siguiente lectura, normalmente esa lectura duraba 2 horas y luego al laboratorio a seguir trabajando.

Cada dia aumentaban nuevos laboratorios, esto era de acuerdo a las lecturas y el nivel en el que uno estaba; por cierto hasta el tercer dia habia dos niveles a los que uno podia asistir, estos eran de lo de inicial y el de los avanzados.

No era facil terminar los laboratorios en los tiempos de laboratorio, asi que yo me llebava la tarea para la casa, osea me dirigia directo a casa y rapidamente para seguir programando y terminar los laboratorios. Y llegando a casa comia algo y luego a seguir programando. t;/p>

Esa era mi rutina de casi todos los dias, una que otra variacion entre dia a dia, especialmente los sabados y domingos.

Algunos temas del curso

El curso de Applied Functional Programming consistio de varias lecturas sobre varios topicos relacionados a Programacion Funcional en general y al lenguaje de programacion Haskell en particular. Los topicos cuviertos incluyeron: calculo lambda, sistema de tipos de Haskell, estructuras de datos funcionales, monads, embedded domain-specific lamguages, como tambien estructuracion, testeo, y profiling de programas funcionales.

En los laboratorios hicimos varios proyectos relacionados a las lecturas, los cuales les presentabamos a los docentes o a los auxiliares, tambien algunos presentamos un proyecto final a los companieros, yo trabaje en el proyecto de wiki-server.

Por cierto, puedes encontrar todo el material de las lecturas y laboratorios en la pagina del curso.

Otras actividades del curso

Lastimosamente no pude participar de todas las actividades del curso de verano, habia 5 actividades: almuerzo de bienvenida, cena del curso, noche de pitza, tarde de bebidas, almuerzo de despedida.

Solo asisti a 3 de ellas, el almuerzo de bienvenida, tarde de bebidas, y el almuerzo de despedida. Me perdi de las mejores, no asisti a la cena del curso porque estaba muy cansado y me regrese a casa temprano para dormir (pedi permiso), y no asiti a la noche de pitza porque me confundi las fechas, yo estaba seguro que seria el jueves, pero fue el miercoles, y justo ese dia no fui a clases de la tarde porque queria terminar mi proyecto. Y cuando me di cuenta ya era muy tarde para ir.

Tambien tuve otras actividades fuera del curso, el primer domingo [Doaitse Sweirstra] nos llevo a ver Culemborg, tambien visitamos el Museo Bativia-werf (nos subimos a un barco), tuvimos un cafesito a las orillas del oceano, participamos del IFL (que lo contare en otro post), y como parte del IFL visitamos la torre Dom, visitamos un museo de arte, tuvimos un paseo en barco por casi todo Utrecht y Amsterdam, y visitamos en automovil varios lugares que no conosco sus nombres pero que tenian una hermosa vista.

Mi fiel companiero de viaje, curso, etc

Ahora es tiempo de mensionar de un companiero fiel, que no se separaba mucho de mi, siempre andabamos juntos (en el buen sentido de la palabra), y casi todo lo que yo hacia el tambien lo hacia y visiversa.

Antonio fue mi companiero de viaje desde la ida en Cochabamba y hasta la vuela Santa Cruz, incluso fue mi companiero de cuarto durante el curso y otras visitas, tambien paso todas las lecturas junto con migo, y tambien trabajo junto con migo en ciertos proyectos, hasta teniamos casi los mismos amigos. Fue mi fiel companiero Antonio.

En resumen

Asi como uno de mis profesores lo dijo: “Ha sido toda una experiencia completa para toda la vida”, eso resume lo super que ha sido este tiempo.

Quiero agradecer a todos los que han ayudado para que todo esto se lleve adelante. Sin su ayuda nada hubiera sido como ha sido. Y ahora a aplicar todo lo aprendido y a cumplir todo lo prometido.

Hasta otra oportunidad,

Saludos Carlos Gomez

L-System 2

May 16, 2010 por Carlos Gomez   Comentarios (0)

,

Hice unos avances en este proyecto, implemente la parte de movimiento turtle.

Turtle, es un lenguaje para generar recorridos. Basicamente turtle tiene un estado y comandos a ejecutar sobre el estado.

El estado es la posicion (x,y) del objeto, la distacia a recorrer y un angulo que guia la direccion.

Los comando son:
F  -> avanzar adelante y dibujar una linea entre el punto del estado y el nuevo generado por la distancia y angulo.
f  -> avanzar adelante pero sin dibujar ninguna linea.
+ -> incrementar el angulo de estado con otro angulo constante.
- -> decrementar el angulo del estado con otro angulo constante.

Entonces, la anterior version generaba el resultado de un sistema L, ahora en esta nueva version, genero elementos del lenguaje turtle. Y una ves generados estos elementos, los interpreto con una libreria grafica, wxhaskell.

Les dejo algunas imagenes de los resultados obtenidos:

lsystem-koch

 

kochilkoche

L-System

May 15, 2010 por Carlos Gomez   Comentarios (0)

,

L-System

Hoy por la noche, cuando navegaba por la red me encontre con algo interesante. Y decidi iniciar un proyecto pequeño, un L-System en Haskell.

Este proyecto me trae recuerdos cuando estaba en la materia de Interfaces de Usuario con el Lic. Boris Calancha, en la que desarrollamos fractales con Java, de una forma recursiva. En aquel entonces no tenia la menor idea de que existia una generalizacion en la forma de generar fractales, pues hoy aprendi que si hay una generalizacion muy interesante, me intereso mas que todo por que esta relacionado con el campo de estudio que sigo, gramaticas, compiladores y haskell.

Pues resulta que un L-System es una tri-tupla, (muy parecido a las gramaticas que estudiamos en automatas)

G (V, w, P)

donde:

V: Alfabeto o conjunto de Simbolos
w: Simbolo Inicial
P: Reglas de Produccion o de re-writing

Asi, esta tri-tupla es capaz de generar fractales. La forma de hacerlo es atraves de derivaciones empezando con el simbolo inicial (no olviden que para hacer una derivacion usamos las reglas de produccion). Entonces de acuerdo al fractal que queramos, podemos aplicar (derivar) varias veces.

Veamos un ejemplo de wikipedia,

Example 1: Algae
variables : A B => alfabeto

constants : none
start : A => simbolo inicial
rules : (A → AB), (B → A) => 2 reglas de produccion
which produces:
n = 0 : A
n = 1 : AB
n = 2 : ABA
n = 3 : ABAAB
n = 4 : ABAABABA
n = 5 : ABAABABAABAAB
n = 6 : ABAABABAABAABABAABABA
n = 7 : ABAABABAABAABABAABABAABAABABAABAAB

Cuando vemos este ejemplo, no parece animar ni convencer para seguir con el proyecto, sin embargo, si vale la pena seguir cuando se ve las imagenes que se puede generar (fractales), y eso se logra con la ayuda de una libreria grafica y un sistema denominado turtle para interpretacion de strings. Si quieres convencerte al igual que yo, debes ver las imagenes de wikipedia.

Bueno, y esta oportunidad queria compartirles la implementacion de una parte basica de este sistema L,

la forma en que represento un sistema L es asi:

type L = (V, W, P)              -- Sistema L

type V = [String]
type W = String
type P = [(Char, String)] -- simbolo -> resultado == (simbolo, resultado)

genero un parser de acuerdo a las producciones:

--genParser :: [(Char, String)] -> Parser ? ?
genParser lst = if null lst
then usererror "GenParser: the argument my not be empty list."
else foldr1 (<|>) (map fun lst)
where fun (val, res) = (res <$ pSym val)

y genero las iteraciones enviandole el sistema L y un N que indica el numero de iteraciones, esta funcion imprime el resultado en la pantalla.

generate :: L -> Int -> IO ()

Veamos algunos ejemplos de sistemas L:

{-
Example 1: Algae

variables : A B
constants : none
start : A
rules : (A → AB), (B → A)
-}

algae = (["A", "B"], "A", [('A', "AB"),('B',"A")])

{-
Example 2: Fibonacci numbers

variables : A B
constants : none
start : A
rules : (A → B), (B → AB)
-}

fib = (["A","B"], "A", [('A', "B"),('B',"AB")])

{-
Example 3: Cantor dust

variables : A B
constants : none
start : A
rules : (A → ABA), (B → BBB)
-}

cantor1 = (["A","B"], "A", [('A', "ABA"),('B',"BBB")])
cantor2 = (["-"," "], "-", [('-', "- -"),(' '," ")])

Ahora mostremos algunos ejemplos:

*Parser> generate fib 7
BABABBABABBABBABABBAB

*Parser> generate algae 7
ABAABABAABAABABAABABAABAABABAABAAB

*Parser> generate cantor1 4 ABABBBABABBBBBBBBBABABBBABABBBBBBBBBBBBBBBBBBBBBBBBBBBABABBBABABBBBBBBBBABABBBABA

*Parser> generate cantor2 4
- - - - - - - - - - - - - - - -
(Nota.- este utlimo no se grafico bien, pero se genera correctamente en consola)

Bueno eso es todo por hoy, si quieres ver el codigo y el proyecto, te invito que sigas este link.

Phantom Types con uuagc

March 24, 2010 por Carlos Gomez   Comentarios (3)

, , ,

Despues de entender Phantom Types, me puse a ver la manera de hacerlo con AGs (Attribute Grammar), y la verdad no es cosa de otro mundo. Pero veamoslo paso a paso.

Un Phantom Type, es una tecnica que nos permite hacer chequeo de tipos en tiempo de compilacion manteniendo una gramatica abstracta sencilla y comprensible.

Veamoslo con el ejemplo de la pagina fuente, tenemos un evaluador de expresiones, el cual es reescrito usando gramatica de attributos de esta manera:

DATA Expr
    | Val Int
    | Add le,lr : Expr
    | LE e1, e2 : Expr
    | Cond ex, iex, eex : Expr

DERIVING * : Show

ATTR Expr [ | | value : {Res}]

SEM Expr
    | Val lhs.value  = ResI @int
    | Add lhs.value  = case (@le.value, @lr.value) of
                               (ResI x, ResI y) -> ResI (x + y)
                               _                    -> error "Bad Arguments to Add"
    | LE lhs.value   = case (@e1.value, @e2.value) of
                               (ResI x, ResI y)  -> ResB (x <= y)
                               _                     -> error "Bad Arguments to LE"
    | Cond lhs.value = case (@ex.value) of
                               ResB b -> if b then @iex.value else @eex.value
                               _        -> error "Bad Arguments to Cond"

{
data Res = ResI Int | ResB Bool  deriving Show

main :: IO()
main = print e1
    where e1 = sem_Expr (Cond (LE (Val 3) (Val 5)) (Add (Val 1) (Val 2)) (Val 0)) t;br />             e2 = sem_Expr (Cond (Val 1) (Val 1) (Val 1))
}

Para probarlo, hacemos "uuagc -mdfcs AExpr.ag", y luego lo cargamos con "ghci AExpr.hs" y lo ejecutamos con "main", y el resultado sera "ResI 3".

Hasta aqui, todo anda bien, pero que pasa si en el ag cambiamos "e1", por "e2" en el "main"?despues ejecutarlo nos da un error de "Bad arguments to Cond", asi como lo esperabamos. Pero que pasaria si no queremos obtener estos errores, y que si quisieramos capturar estos errores en tiempo de compilacion?, una forma comun de hacerlo seria cambiando nuestro tipo algebraico y escribiendo una gramatica abstracta que tenga expresiones booleanas, enteras y demas cosas. Pero una forma es usando la tecnica de Phantom Type, como lo mensionamos mas antes, mantenemos una gramatica sencilla y nos permite usar el chequeo de tipos de Haskell.

Entonces, lo reescribimos de esta manera:

DATA Expr'
    | Val Int
    | Add le,lr : Expr'
    | LE e1, e2 : Expr'
    | Cond ex, iex, eex : Expr'

DERIVING * : Show

ATTR Expr' [ | | value : {Res}]
SEM Expr'
    | Val lhs.value  = ResI @int
    | Add lhs.value  = case (@le.value, @lr.value) of
                            (ResI x, ResI y) -> ResI (x + y)
                            _                    -> error "Bad Arguments to Add"
    | LE lhs.value   = case (@e1.value, @e2.value) of
                            (ResI x, ResI y)  -> ResB (x <= y)
                            _                     -> error "Bad Arguments to LE"
    | Cond lhs.value = case (@ex.value) of
                            ResB b -> if b then @iex.value else @eex.value
                            _        -> error "Bad Arguments to Cond"

{
data Res = ResI Int | ResB Bool  deriving Show

newtype Expr a = E Expr'
    deriving (Show)

-- wrappers
val :: Int -> Expr Int
val = E . Val

add :: Expr Int -> Expr Int -> Expr Int
add (E x) (E y) = E $ Add x y

le :: Expr Int -> Expr Int -> Expr Bool
le (E x) (E y) = E $ LE x y

cond :: Expr Bool -> Expr a -> Expr a -> Expr a
cond (E c) (E x) (E y) = E $ Cond c x y

eval :: Expr a -> Res
eval (E e) = sem_Expr' e

main :: IO()
main = print e1
    where e1 = eval (cond (le (val 3) (val 5)) (add (val 1) (val 2)) (val 0))
             --e2 = eval (cond (val 1) (val 1) (val 1))
}

Y ahora, ejecutamos lo mismo que la ultima ves y obtenemos el mismo resultado. Pero si cambiamos "e1" por "e2" en el "main", descomentamos "e2" e intentamos compilarlo, obtendremos un error de tipos en tiempo de compilacion, asi podremos contruir solo expresiones validas para nuestro evaluador.

Donde esta la tecnica de Phantom Type?, los hacemos atraves de "newtype Expr a = E Expr' ", el cual crea un nuevo tipo parametrizando el tipo deseado, el cual es controlado por el type chequer de Haskell. Este nuevo tipo, tiene en su contructor de datos algo asi como un tipo fantasma (Phantom Type), esto pienso asi porque:

-- el tipo del contructor de datos de Expr seria
E :: Expr' -> Expr a

-- por ejemplo el tipo de val, es
val :: Int -> Expr Int

Asi el tipo de "Expr a" no refleja el contenido que tiene empaquetado, por eso pienso que el tipo de adentro es el fantasma.

Volviendo al tema, el siguiente paso despues de crear el tipo fantasma, es escribir las funciones wrapper, los cuales se encargan de contruir el "Expr' " que queremos. Y tambien es aqui donde detallamos el chequeo de tipos para Haskell.

En el AG podemos borrar los casos erroneos de los expresiones case, sin afectar los resultados. Y para una mejor presentacion y cuidado, podemos exportar junto con el modulo, solo las funciones wrappers y tipos necesarios.

Bueno, esta es la manera en que implemente Phantom Types con AGs. Si ves el documento fuente, te preguntaras como implemetar GADTs con AGs, pues es algo que yo aun sigo preguntandome, y la verdad no se si habra una manera de hacerlo con AGs, pero como al autor de decia, Phantom Types es una solucion elegante, relativamente sencilla y estandard de Haskell en comparacion con GADTs.

 

Estructuras de Datos Funcionales vs. Imperativas

February 9, 2010 por Carlos Gomez   Comentarios (0)

En esta oportunidad quiero compartir una traduccion de una de los subtitulos del libro: Purely Functional Data Structure [Chris Okasaki], que me parecio muy buena.

Estructuras de Datos Funcionales vs. Imperativas

Los beneficios metodologicos de los lenguajes funcionales son bien conocidos, pero aun la mayoria de los programas son escritos en lenguajes imperativos como C. Esta aparente contradiccion es facilmente explicado por el hecho de que los lenguajes funcionales han sido historicamente mas lentos que sus mas tradicionales primos, pero esta brecha se esta reduciendo. Se han hecho impresionantes avances desde un amplio frente, desde tecnologias basicas de compiladores a analisis sofisticados y optimizaciones. Sin embargo, hay un aspecto de la programacion funcional que todo escritor de compiladores debe mitigar - el uso de estructuras de datos inapropiadas o inferiores.

Porque las estructuras de datos funcionales son mas dificultuosas para diseñar e implementar que las imperativas? Hay 2 problemas basicos. Primero, desde el punto de vista de diseño e implementacion de estructuras de datos eficientes, la estructura de la programacion funcional contra actualizaciones destructivas (ej. asignaciones) es una desventaja asombrosa, equivalente a confiscar los cuchillos de un chef master. Al igual que los cuchillos, las actualizaciones destructivas pueden ser dañinas cuando son mal usadas, pero tremendamente efectivas cuando son usadas apropiadamente. Las estructuras de datos imperativas a menudo confian en la asignacion de una forma crucial, y por eso se encuentran diferentes soluciones para los programas funcionales.

La segunda dificultad es que se espera que las estructuras de datos funcionales sean mas flexibles que sus contrapartes imperativas. En particular, cuando actualizamos una estructura de datos imperativa, tipicamente aceptamos que la version antigua de la estructura de datos ya no estara disponible, pero cuando actualizamos una estructura de datos funcional, esperamos que la antigua y nueva version de la estructura de datos estara disponible para futuros procesamientos. Una estructura de datos que soporta multiples versiones es llamado persistente [persistent], mientras que una estrutura de datos que permite solo una simple version en un tiempo es llamado efimera [ephemeral]. Los lenguajes de programacion funcional tienen la propiedad curiosa de que todas las estructuras de datos son auntomaticamente persistentes. 
Las estructuras de datos imperativas son tipicamente efimeras, pero cuando una estructura de datos persistente es requerida, los programadores imperativos no se sorprenden si la estructura de datos persistente es mas complicada y talves incluso asintoticamente menos eficiente que una equivalente estructura de datos efimera.

Ademas, los teoricos han establecido limites inferiores sugeriendo que los lenguajes de programacion funcional podrian ser fundamentalmente menos eficientes que los lenguajes imperativos en algunas situaciones. En vista de todos estos puntos, las estructuras de datos funcionales se parecen algunas veces al oso que baila, de quien se dice, "lo maravilloso no es que el danza muy bien, sino de que el danza de alguna manera!". En la practica, sin embargo, la situacion no es tan triste. Como podremos ver, es a menudo posible eleborar estructuras de datos funcionales que son asintoticamente tan eficientes como las mejores soluciones imperativas.

 

Setters and Getters en Haskell

August 6, 2009 por Carlos Gomez   Comentarios (2)

, , , , , ,

 

Nota.- Para su mejor comprencion he hecho varios cambios aqui, uno de ellos es el nombre del contructor de datos, de Persona a Per.

Ahora, Como definimos los setters y getters de una estructura de datos Persona?

Responderemos a esta pregunta, en el resto de este blog, asi nuestra estructura de datos es Persona con los datos de ci, nombre, apellido y edad.

data Persona = Per CI Name LastName Edad
                                        deriving Show
type CI           = Int
type Name       = String
type LastName = String
type Edad        = Int

Esto define una funcion constructora de datos de tipo:

Per ::CI -> Name -> LastName -> Edad -> Persona

Veamos algunos ejemplos:

p1 :: Persona
p1 = Per 1212 "Juan" "Block" 35

p2 :: Persona
p2 = Persona 2323 "Pedro" "Ramos" 25

Ahora definamos algunas funciones set y get para Persona

setCI :: Persona -> CI -> Persona
setCI (Persona ci nm ap ed) ci' = Per ci' nm ap ed

setNombre :: Persona -> Name -> Persona
setNombre (Persona ci nm ap ed) nm' = Per ci nm' ap ed

setApellido :: Persona -> LastName -> Persona
setApellido (Persona ci nm ap ed) ap' = Per ci nm ap' ed

setEdad :: Persona -> Edad -> Persona
setEdad (Persona ci nm ap ed) ed' = Per ci nm ap ed'

getCI :: Persona -> CI
getCI (Persona ci _ _ _) = ci

getNombre :: Persona -> Name
getNombre (Persona _ nm _ _) = nm

getApellido :: Persona -> LastName
getApellido (Persona _ _ ap _) = ap

getEdad :: Persona -> Edad
getEdad (Persona _ _ _ ed) = ed

Si hacemos algunas pruebas obtenemos:

gt;*Main> getCI p1

nos retornaria el CI de 'Juan', tambien podemos obtener nombre, apellido o edad.

Para setear un valor, podemos hacer

*Main> p1 {nombre = "juanes"}
Persona {ci = 1212, nombre = "juanes", apellido = "Block", edad = 35}

Y listo, mision cumplida, aunque un poco tedioso. 
Bueno, esto no termina aqui, resulta que Haskell provee una forma diferente de definir los datatypes, esto es nombrando los elementos de cada constructor de datos. Llamado tambien records de Haskell.

Veamos como nos ayuda esto, en nuestra definicion de setters y getters, y como cambia a lo anterior ya hecho.

data Persona = Per { ci        :: CI
                           , nombre :: Name
                           , apellido :: LastName
                           , edad     :: Edad
                           } deriving Show
type CI           = Int
type Name       = String
type LastName = String
type Edad        = Int

Bueno, eso es todo lo que tenemos que hacer, hagamos algunas pruebas para ver algo de teoria.

p3 = Per 2525 "Teo" "Flores" 43  -- creamos un instancia
* Main> ci p3
2525
* Main> p3{nombre = "Maria"}
Persona {ci = 2525, nombre = "Maria", apellido = "Flores", edad = 43}

Como veras, hicimos las operaciones de set y get.

Algo de teoria, el nombramiento de campos en los datatypes no afecta al anterior version, por ejemplo el tipo contructor de datos es el mismo. Pero hay funcionalidades que se aumentan. Entre ellos tenemos la seleccion de campos usando labels, construccion usando labels y actualizacion de campos usando labels.

La seleccion de campos usando labels, es practicamente la operacion seter de un objeto. Y lo que Haskell hace es definir una funcion con el nombre del label, el cual esta disponible para su uso. Ejemplo "ci p3".

Tambien podemos contruir instancias usando labels (p4 = Per {edad=12, ci=3434, apellido="Perez", nombre="Pedro"} ), y no solo de la forma comun (p4 = Per 3434 12 "Pedro" "Perez"). Intensionalmente he cambiado las posiciones de los labels, pues esto no afecta. Se debe cuidar de que ningun label se repita mas de una ves, pero si no especificamos algun label, este deberia inicializar como indefinido o infito (GHC lo muestra como un warning).

Para la actualizacion de campos usando labels, se tiene una sintaxis: instancia_obj {label=value, ...}, asi como en el ejemplo p3{ci=3454}. Otra ves, no se debe mencionar mas de una ves una label, y los labels deben pertenecer al tipo contructor.

Al actualizar un valor de la instancia, se genera una nueva instancia modificando asi en la nueva instancia los valores enviados. Es una caracteristica de Persistencia de Haskell. Veamos un ejemplo:

*Main> p1 {edad = 0}
Persona {ci = 1212, nombre = "Juan", apellido = "Block", edad = 0}
*Main> p1
Persona {ci = 1212, nombre = "Juan", apellido = "Block", edad = 35}

Tambien podemos mesclar los distintos contructores de datos con esta sintxis o sin ella. Y respecto a los nombres de los labels, podemos repetirlas entre las funciones contructoras de datos, siempre y cuando se tenga un tipo consistente, pero no podemos repetirnas entre los datatypes, porque generaria una incosistencia de tipos. Veamos un ejemplo sacado del reporte de Haskell 98:

data S = S1 {x :: Int}
          | S2 {x :: Int}   -- ejemplo bueno

data T = T1 {y :: Int}
          | T2 {y :: Bool}  -- ejemplo malo, tipo inconsistente

En conclusion, esta forma de creacion de datatypes, añade funcionalidad y sintaxis extra para manipular los elementos del datatype.

Algo interesante seria averiguar como definir mucha mas similitud de funcionalidad a OOP. Me refiero a definir solo funciones set o get para algunos elementos, o declarar elementos como publicos, protegidos o privados.

Hay otras extenciones de GHC que nos facilitan la manipulacion de records en Haskell. Pero los que hemos visto aqui pertenece al Haskell 98.

Cabal (Common Architecture for Building Applications and Libraries)

July 29, 2009 por Carlos Gomez   Comentarios (2)

, ,

 

Hoy revizaremos una forma de instalar Cabal, una herramienta muy comoda para instalar y construir aplicaciones y librerias de haskell.

Para una informacion mas detallada puedes ver Biliotecas adicionales con Cabal.

Pero hagamos lo nuestro:

La forma que abordaremos es instalar cabal atraves de un bootstrap, el cual se encargara de descargar las fuentes, configurarlas e instalarlas.

Antes de continuar debemos preveer que disponemos de 3 cosas basicas (Doy por supuesto que tienen instalado ghc 8 o superior):

Nota.- Los siguientes comandos son para un sis ope basado en Debian (esto incluye a ubuntu).

1.- parsec library of ghc.
     Si no tienes instalado, puedes instalarlo con:
        apt-get install libghc6-parsec-dev libghc6-parsec-doc

2.- network library of ghc.
     Si no tienes instalado, puedes instalarlo con:
        apt-get install libghc6-network-dev libghc6-network-doc libghc6-network-prof

3.- zlib.h header of C.
        Podemos encontrar el header zlib.h en la libreria zlib1g-dev.
        Comandos para instalarlo:
        apt-get install zlib1g-dev

Despues de preever las anteriores cosas podemos descargar el Cabal Install Tool de la pagina http://www.haskell.org/cabal/download.html.

Descargar Cabal Install Tool 0.6.2.tar.gz, y ejecutamos el bootstrap.sh

Ejecutando ./bootstrap.sh se descargara las fuentes de cabal de la web, luego se configuran y finalmente se instalaran en tu sistema (Debes notar que necesitaras una coneccion a internet cuando estes ejecutando el bootstrap).

 

Ahora que ya esta instalado cabal, debemos publicar el comando cabal ubicado en /root_or_user_/.cabal/bin. Podriamos crear un enlace a este comando en /usr/bin con
         ln -s /root/.cabal/cabal cabal

Antes de usarlo debemos actualizar la lista de paquetes con
       cabal update

Ahora podremos disfrutar de Cabal, e instalar otras aplicaciones.

IRC Channel Haskell

June 19, 2009 por Carlos Gomez   Comentarios (0)

, ,

Navegando por la Web encontre un Canal IRC.

No sabia que existia un lugar online en donde se puede chatear con otros haskelleros.

Segun ellos, este IRC puede ser usado para aprender mas acerca de haskell, enterarse de nuevas cosas de haskell, porque muchas nuevas cosas primero dice que aparecen en el irc.

Bueno, no quise esperar mucho para unirme.

Para unirte puedes usar cualquier chat que te permita unirte al irc, en lo particular yo use irssi, pero puedes usar pidgin u otro.

apt-get install irssi

luego, > irssi -c chat.freenode.net -n tunickname

puedes usar cualquier nick que no este repetido actualmente, pero si despues dela primera ves quieres mantenerte con ese nick deberas registrarte, como ?, puedes ver frenode-register

una ves adentro seleccionar el salon al que quieres ingresar, en nuestro caso

/join #haskell

y listo, a chatear con los cuates.

Para mas informacion puedes ver este enlace irc-haskell, en el cual encontraras otros salones de chat relacionados a haskell.

 

 

ICFP Programming Contest

June 15, 2009 por Grace Pahuasi   Comentarios (2)

Que les parece ... ya se publico las fechas para el ICFP Programming Contest 2009

no falta mucho asi que a cargar pilas !! 

Donde y cuando  practicamos ?