7 may. 2009

Type Classes en Haskell (Enum, Eq, Show)

Cuando definimos un tipo de dato, digamos:


data Alumnos = PP | Jorge | Raul | Laura |Ricardo|Rodrigo



nos gustaria poder hacer operaciones sobre ellos que nos permitan compararlos, imprimir en pantalla, ordenarlos etc. Si declaramos en Haskell el tipo de dato Alumnos tal como esta anteriormente y preguntamos a nuestro interprete :



Main> PP == PP



Esperariamos que nos devolviera True, sin embargo nos devolvería un error similar a:


ERROR - Cannot infer instance
*** Instance : Eq Alumnos
*** Expression : PP == PP



Que de manera intuitiva significa que haskell no sabe cuando dos Alumnos son iguales. Peor aún si ponemos en el interprete:


Main> PP



Esperariamos que devolviera PP, pero no lo hace!! si no que nos muestra el siguiente error:



ERROR - Cannot find "show" function for:
*** Expression : PP
*** Of type : Alumnos



Que de manera intuitiva significa que haskell no sabe como mostrar a un Alumno en pantalla.

Ahora supongamos que queremos ordernar a nuestros alumnos de tal forma que el primero sea Rodrigo, el segundo Raul, luego Jorge,...etc Es decir queremos enumerar a los elementos de nuestro tipo de datos, por ejemplo el tipo Char en Haskell es un tipo enumerado, si queremos saber cual es el caracter 97 ponemos lo siguiente:




Main>toEnum 97::Char
'a'



Pero también nos gustaría tener la función inversa, es decir dado un alumno saber que numero tiene asignado (Pongo el ejemplo para Char).



Main>fromEnum 'a'
97



Todo lo anterior se puede hacer si le decimos a Haskell que él se encarque de todo y eso lo logramos declarando el tipo de datos Alumnos de la sigueinte manera:



data Alumnos =
PP | Jorge | Raul | Laura |Ricardo|Rodrigo deriving(Show,Eq,Enum)




Lo que estamos diciendo es que el tipo de dato Alumnos es una instancia/o pertenece a las clase:
Show, es decir son cosas que se pueden mostrar en pantalla.
Eq, son cosas que se pueden comparar.
Enum, son objetos que se pueden ordenar/enumerar.

Con la nueva definción ponemos en el interprete:



Main> PP



haskell nos regresará



PP



si ponemos



hugs> PP == PP



regresará True

Pero quizá somos obsesivos, por lo que nos gustaría que PP se mostrara como "pepe" o como "jose". O bien que el primero de la lista no sea PP sino Rodrigo, y que la igualdad entre alumnos no sea sintáctica si no más bien dos alumnos son iguales si la primer letra de su nombre es igual (o cualquier otro criterio bizarro que se les ocurra) Esto lo logramos definiendo las funciones show (para mostar) ==(para comparar si son iguales) toEnum (para enumerar) fromEnum(para saber la numeración de un elemento) y lo hacemos de la siguiente manera:

Se declara el tipo datos como al principio



data Alumnos = PP | Jorge | Jessica |Raul | Laura |Ricardo|Rodrigo

instance Show Alumnos where show = muestra


muestra PP = "pepito"
muestra Jorge = "YoRcH"
muestra Raul = "rul"
muestra Rodrigo = "rod"
muestra Ricardo = "richi"
muestra Laura = "laura"
muestra Jessica = "jess"



Otra forma de hacerlo es


instance Show Alumnos where
show PP = "pepito"
show Jorge = "YoRcH"
show Raul = "rul"
.
.
.



Ojo con la identación en esta forma (show esta a la altura de Show pero por culpa de blogger esto no se ve claramente)!!! Si ponemos en el interprete :



Main> PP
pepito


Para definir == lo hacemos de manera análoga:



instance Eq Alumnos where (==) = igual

igual PP Jorge = True
igual Rodrigo Raul = True
igual _ _ = False



nótese que nuestra definición de igualdad esta bien chafa... pero total.... (no es conmutativa, etc etc).

De manera análoga para la clase Enum definimos



instance Enum Alumnos where
fromEnum =danumero
toEnum = anumero

danumero Rodrigo = 0
danumero Ricardo = 1
danumero Laura = 2
danumero Jessica = 3
danumero Raul = 4
danumero Jorge = 5
danumero PP = 6

anumero 0 = Rodrigo
anumero 1 = Ricardo
anumero 2 = Laura
anumero 3 = Jessica
anumero 4 = Raul
anumero 5 = Jorge
anumero 6 = PP



Cuidado con la identación que luego uno pasa verguenzas por detalles como esos!! Es importantisimo que para que toEnum funcione bien la función show debe estar definida bien (cubra todos los casos).



Main> toEnum 0::Alumnos
rod
Main> toEnum 1::Alumnos
richi
Main> toEnum 6::Alumnos
pepito

Main> fromEnum PP
6
Main> fromEnum Jessica
3



Observese como se hace uso de la función toEnum. Para quien quiera ver de manera correcta la identación aqui esta el .hs donde vienen estos ejemplos. En el proximo de Haskell : Mónadas (no monádas!) .

6 comentarios:

Shy Guy dijo...

Haskell es muy chévere, creo que ya me está gustando más que Java... bueno, no, Java tiene su lugar en mi corazoncito al igual que C, aunque más bien por razones emotivas.

Saludos.

PAGE dijo...

Haskell es chidisimo, es mi lenguaje de programación favorito, pero reconozco que tiene ciertas limitantes todavía, y que su uso es mas en la Academia que en la industria$$$ .C es tambien bueno pero eso de los apuntadores y manejo de memoria no me late tanto.... pero sin duda es mejor que Java, que tambien esta padre pues como diria un amigo "cualquier simio aprende Java"

Estrella Fugaz dijo...

Wow!!!

Es lo que buscaba hace unas semanas para mi práctica de Lógico!!! jijiji!!

Genial!!!

Saludos!!!

PAGE dijo...

jeje, un poco tarde la explicación.... pero bueno...

Tlacaelel dijo...

Que, ¿firmas autógrafos?

PAGE dijo...

jajaja

ga