% Práctico Haskell 2: Monoid, IO, Functor, Aplicative, Monad
Monoid
En el teórico hemos hablado del que un tipo como Int
puede
tener ser instancia de la clase Monoid
de dos maneras distintas.
Descargar y resolver MonoidInt.hs.
Instancias solapadas
Descargar y resolver Solapamiento.hs
Vamos a tener que usar la extensión FlexibleInstances
.
Agregar {-# LANGUAGE FlexibleInstances #-}
al principio del archivo.
Permite que la cabeza de una declaración de instancia mencione tipos anidados arbitrarios:
instance C (Maybe Int)
IO
y Monoid
, IO
y Functor
Este ejercicio consiste en definir funciones de tipo IO algo
en una sola línea solo usando funciones de las clases Monoid
y Functor
.
Descargar y resolver MonFunIO.hs.
Functor
En un módulo Functor.hs
:
-
Implementar una instancia de
Functor
paraEither
. ¿Será exactamenteEither
el tipo que puede ser instancia deFunctor
? Pensar en la aridad (kind). -
Definir estos dos tipos, e implementar sus instancias de
Functor
data ComplicatedA a b
= Con1 a b
| Con2 [Maybe (a -> b)]
data ComplicatedB f g a b
= Con3 (f a)
| Con4 (g b)
| Con5 (g (g [b]))
Mónada Maybe
Escribí una función que detecta si una String tiene cierto formato. El formato requerido es el siguiente:
- La string empieza con un dígito.
- Llamemos
n
el valor de ese dígito. La string contiene luegon
caracteres'a'
. - Después de las
'a'
, o la string se termina, o la secuencia se repite, empezando con un dígito (puede ser distinto).
Ejemplos:
Buenas strings Malas strings ————– ————- 3aaa2aa 3aaa2a 9aaaaaaaaa 10aaaaaaaaaa 0 1 001a 100a 2aa2aa 2bb2bb
Tu función debe usar la mónada Maybe
. Debería parecerse a esto:
stringFitsFormat :: String -> Bool
stringFitsFormat = isJust . go
where go :: String -> Maybe String
-- go evalua a Just "" si es exitosa, sino a Nothing
...
Ayuda: usá readMaybe :: Read a => String -> Maybe a
de
Text.Read
y stripPrefix :: Eq a => [a] -> [a] -> Maybe [a]
de Data.List
.
Monada IO
y notación do
: Top 10 de las palabras de un archivo
Algunas referencias útiles para resover este ejercicio:
- capítulo “Entrada y Salida” (hasta Aleatoriedad).
- capítulo “Módulos”,
en particular
Data.List
yData.Map.Strict
- el buscador de funciones Hoogle: https://www.haskell.org/hoogle/
-
Hacé un programa que lee un archivo de texto, e imprime su contenido en la salida estándar.
-
Modificalo para que haga lo mismo pero pasando todos los carácteres a mayúsculas (usando la función
toUpper
del móduloData.Char
. -
Vamos a hacer un programa que hace un poco más de procesamiento de datos.
La idea es hacer un programa que lee un archivo de texto y muestre las 10 palabras más frecuentes.
Como archivos de texto pueden bajar libros desde proyecto Gutenberg (https://www.gutenberg.org/) en formato
.txt
. Por ejemplo Guerra y Paz de Leo Tolstoy tiene suficiente contenido para que tengamos resultados interesantes.Se puede dividir el trabajo en 3 partes:
- leer el contenido del archivo como una lista de palabras
- contar cuantas veces aparecen cada palabra
- ordenar las palabras de más frecuente a menos frecuente, y mostrar las 10 más frecuentes
Para implementar el paso 2, vamos a usar la estructura de datos
Map
(diccionario) deData.Map.Strict
, porque es una estructura optimizada que puede soportar grandes cantidades de datos. Más precisamente, la idea es guardar las palabras y su número de ocurrencias en un diccionario de tipoMap String Int
.Pasos:
a. Importá los módulos
Data.Map.Strict
yData.List
dándoles un prefijo para cada uno para evitar colisiones de nombres (ver “import qualified” en Aprende Haskell). Definí una funciónmain
que lee el contenido de un “input.txt” y define las palabras como una lista de Strings. b. Definí una funciónagregar :: Map String Int -> String -> Map String Int
que agrega una palabra a un diccionario (posiblemente el diccionario ya tiene la palabra!). Fijate (en Hoogle) en la documentación deData.Map.Strict
qué función(es) te puede(n) ayudar para definiragregar
. c. Modificá elmain
para agregar a un diccionario vacío (buscar enData.Map.Strict
) todas las palabras del archivo (¿qué función de orden superior permite hacer eso?). d. Definí la funcióntop10 :: Map String Int -> [(Int, String)]
tal quetop 10 m
sean las 10 palabras más frecuentes del diccionariom
. Definirtop10
requiere (entre otras cosas) ordenar una lista. Fijate en el módulo Data.List qué función(es) puede(n) ser útil(es) para eso. e. Imprimí el top 10 de las palabras del archivo en la salida estándar.
Después de terminar cada paso podés mostrar en la salida estándar lo que
llegaste a definir, por ejemplo usando la función show
en combinación
con putStrLn
.
Podés mejorar el programa implementando tu propia función
que corta una String
en lista de palabras, tomando en cuenta la puntuación,
para mejorar la precisión del programa. Por ejemplo, no te sirve que tu programa
cree que “Hola,” (con la coma) es una palabra; tampoco te sirve que “Hola” y “hola”
sean consideradas como dos palabras distintas.