Хаскелл:Вставка каждой строки из файла в список

StackOverflow https://stackoverflow.com/questions/215748

  •  03-07-2019
  •  | 
  •  

Вопрос

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

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

Это было полезно?

Решение

В строке, где возникает ошибка, Haskell ожидает "IO a", но вы даете ему [].Значительно упрощая ситуацию, в блоке do монады ввода-вывода каждая строка является либо:

  • Что-то, что возвращает значение типа "IO a";значение типа "a" внутри него отбрасывается (поэтому "a" часто является "()")
  • A <- выражение, которое делает то же самое, но вместо того, чтобы отбрасывать значение типа "a", присваивает ему имя слева от <-
  • Let, который не делает ничего большего, чем просто присваивает имя значению

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

let list' = inpStr:list

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

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

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

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

Другие советы

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

getLines = liftM lines . readFile

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top