Pregunta

Actualmente estoy trabajando en un proyecto con Haskell y me he encontrado con algunos problemas.Se supone que debo leer e insertar en una lista cada línea de un archivo "dictionary.txt", pero parece que no puedo hacerlo.Tengo este código:

main = do
    let list = []
    loadNums "dictionary.txt" list

loadNums location list = do
    inh <- openFile location ReadMode
    mainloop inh list
    hClose inh

mainloop inh list = do 
    ineof <- hIsEOF inh
    if ineof
        then return ()
        else do 
            inpStr <- hGetLine inh
            inpStr:list
            mainloop inh list

Se supone que debe obtener cada línea (sé que obtiene todas las líneas, ya que reemplazar "inpStr:list" con "putStrLn inpStr" funciona correctamente y muestra todas las líneas) y lo inserta en una lista, pero aparece el siguiente error. :

Couldn't match expected type `IO' against inferred type `[]'

Probablemente porque hGetLine no es una cadena, sino una cadena IO, que no tengo idea de cómo manejar para obtener una cadena adecuada que pueda insertar en mi lista.No tengo idea de cómo podría resolverse esto, o cuál es exactamente el problema, pero si alguien tiene alguna idea de cómo colocar correctamente cada línea de un archivo en una lista, se lo agradecería.

¡Gracias de antemano!

¿Fue útil?

Solución

En la línea donde ocurre el error, Haskell espera "IO a", pero le estás dando un [].Simplificando mucho las cosas, en un bloque do de la mónada IO, cada línea es:

  • Algo que devuelve un valor del tipo "IO a";el valor del tipo "a" que contiene se descarta (por lo que la "a" suele ser "()")
  • Una expresión <-, que hace lo mismo pero en lugar de descartar el valor del tipo "a" le da el nombre a la izquierda del <-
  • Un let, que no hace más que darle un nombre a un valor.

En ese bloque do, "hGetLine inh" devuelve una "cadena IO", y la cadena que contiene se extrae y se le asigna el nombre inpStr.La siguiente línea, dado que no es ni let ni <-, debería tener un tipo "IO a", lo cual no es así (causando así el error del compilador).Lo que puedes hacer en su lugar, dado que ya tienes el String, es let:

let list' = inpStr:list

Esto crea una nueva lista que consta de la cadena seguida de la lista original y le da el nombre de "lista".

Cambie la siguiente línea para usar "lista" en lugar de "lista" (pasándole así la nueva lista).Esa línea llama (recursivamente) al bucle principal, que leerá una línea más, se llamará a sí mismo, etc.Después de leer el archivo completo, devolverá algo del tipo "IO ()".Este "IO ()" se devolverá al bloque do en loadNums.Felicitaciones, acaba de crear una lista con las líneas leídas del archivo, en orden inverso (ya que las estaba agregando al encabezado de la lista) y luego no le hizo nada.

Si desea hacerle algo, cambie "return ()" a "lista de retorno";el retorno generará un valor de tipo "IO [Cadena]", con la lista dentro (el retorno no hace más que encapsular el valor), que puede extraer en loadNums con la sintaxis <-.

El resto se deja como ejercicio al lector.

Otros consejos

A menos que sea para tarea o algo así, no hay razón para usar tanto esfuerzo. ¡La reutilización es perezosa!

getLines = liftM lines . readFile

main = do
    list <- getLines "dictionary.txt"
    mapM_ putStrLn list

Pero como parece que todavía está aprendiendo Haskell, es importante que comprenda lo que CesarB ha escrito.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top