2008-10-18 13 views
11

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 en un archivo "dictionary.txt", pero parece que no puedo hacerlo. Tengo este código:Haskell: insertando cada línea de un archivo en una lista

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 llegar cada línea (sé que se pone cada línea, ya que la sustitución de la "inpStr: lista" con un "putStrLn inpStr" funciona correctamente, mostrando todas las líneas), y la inserta en una lista, pero me sale el siguiente error:

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

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

¡Gracias de antemano!

Respuesta

14

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

  • Algo que devuelve un valor del tipo "IO a"; el valor del tipo "a" dentro de él se descarta (por lo que "a" es a menudo "()")
  • A < - expresión, que hace lo mismo pero en lugar de descartar el valor del tipo "a" le da el nombre a la izquierda de la < -
  • let, que no hace nada más que dar un nombre a un valor

En ese bloque hacer, el "hGetLine inh" devuelve un "IO String" , y la cadena dentro de ella se extrae y recibe el nombre inpStr. La siguiente línea, ya que no es ni let ni a < -, debe tener un tipo "IO a", que no (lo que causa el error del compilador). Lo que puede hacer en su lugar, puesto que ya tiene la cadena, es un let:

let list' = inpStr:list 

Esto crea una nueva lista que consiste en la cadena seguido de la lista original, y le da el nombre de "lista'.

Cambie la siguiente línea para usar "list" en lugar de "list" (pasando así la nueva lista). Esa línea llama (recursivamente) mainloop, que leerá una línea más, se llamará a sí mismo, y así sucesivamente. Después de leer todo el archivo, devolverá algo con el tipo "IO()". Este "IO()" se devolverá al bloque do en loadNums. Enhorabuena, acabas de crear una lista con las líneas leídas del archivo, en orden inverso (ya que te añades al encabezado de la lista), y luego no le hiciste nada.

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

El resto se deja como un ejercicio para el lector.

15

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

getLines = liftM lines . readFile 

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

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

+0

Al explicarle cosas a alguien que parece estar aprendiendo Haskell, evitaría usar (o incluso mostrar) el estilo sin sentido. No quiero asustarlos ;-) – CesarB

+7

+1 por mencionar 'readFile'. Es muy útil salir de la mentalidad imperativa de abrir archivo/leer línea/detectar EOF/archivo cerrado, y dejar que las funciones como 'readFile',' getContents' y 'interaction' manejen el problema por ti. – Nefrubyr

+0

¿Qué significa "mapM_"? Sé que "mapM" asigna una función a la mónada ... ¿pero la que tiene el guión bajo? – drozzy

Cuestiones relacionadas