Haskell: вставка каждой строки из файла в список - PullRequest
11 голосов
/ 19 октября 2008

Я сейчас работаю над проектом с Haskell, и у меня возникли некоторые проблемы. Я должен прочитать и вставить в список каждую строку в файле "dictionary.txt", но я не могу этого сделать. У меня есть этот код:

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

Предполагается получить каждую строку (я знаю, что она получает каждую строку, так как замена «inpStr: list» на «putStrLn inpStr» работает правильно, отображая все строки), и вставить его в список, но я получаю следующая ошибка:

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

Возможно, потому что hGetLine - это не строка, а строка ввода-вывода, с которой я понятия не имею, как обращаться с ней, чтобы получить правильную строку, которую я могу вставить в свой список. Я понятия не имею, как это можно решить или в чем проблема, но если у кого-то есть представление о том, как правильно поместить каждую строку в файле в список, я был бы признателен.

Заранее спасибо!

Ответы [ 2 ]

15 голосов
/ 19 октября 2008

Если это не для домашней работы или чего-то еще, нет причин для того, чтобы прикладывать столько усилий. Повторное использование ленивый!

getLines = liftM lines . readFile

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

Но так как вы, похоже, все еще изучаете Haskell, вам важно понять, что написал CesarB.

14 голосов
/ 19 октября 2008

В строке, где происходит ошибка, Haskell ожидает «IO a», но вы даете ему []. Многое упрощая, в блоке do монады ввода-вывода каждая строка имеет вид:

  • Что-то, что возвращает значение типа "IO a"; значение типа "a" внутри него отбрасывается (поэтому часто "a" равно "()")
  • A <- выражение, которое делает то же самое, но вместо отбрасывания значения типа «a» присваивает ему имя слева от <- </li>
  • let, которая ничего не делает, кроме как присваивает имя значению

В этом блоке do «hGetLine inh» возвращает «IO String», и строка в нем извлекается и получает имя inpStr. Следующая строка, поскольку это ни let, ни a <-, должна иметь тип "IO a", чего нет (что приводит к ошибке компилятора). Вместо этого вы можете сделать следующее, поскольку у вас уже есть строка: </p>

let list' = inpStr:list

Это создает новый список, состоящий из String, за которым следует исходный список, и дает ему имя «list».

Измените следующую строку, чтобы использовать «список» вместо «список» (таким образом передавая ему новый список). Эта строка вызывает (рекурсивно) mainloop, который будет читать еще одну строку, вызывать себя и так далее. После прочтения всего файла он вернет что-то с типом «IO ()». Этот «IO ()» будет возвращен блоку do в loadNums. Поздравляем, вы только что создали список со строками, прочитанными из файла, в обратном порядке (так как вы добавляли заголовок списка), а затем ничего не сделали с ним.

Если вы хотите что-то с этим сделать, измените return () на return list; return генерирует значение типа "IO [String]" со списком внутри него (return не делает ничего, кроме инкапсуляции значения), которое вы можете извлечь в loadNums с синтаксисом <-. </p>

Остальное оставлено читателю в качестве упражнения.

...