В настоящее время я работаю над проектом с 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 монады ввода-вывода каждая строка либо:
В этом блоке do "hGetLine inh" возвращает "IO String", а строка внутри него извлекается и получает имя inpStr. Следующая строка, поскольку это не let и не <-, должна иметь тип «IO a», которого нет (что вызывает ошибку компилятора). Что вы можете сделать вместо этого, поскольку у вас уже есть String, это let:
let list' = inpStr: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.
+1 за упоминание readFile. Так полезно избавиться от императивного мышления: открыть файл / прочитать строку / обнаружить EOF / закрыть файл, и позволить функциям вроде readFile, getContents и interact справиться с беспорядком за вас.
Что означает "mapM_"? Я знаю, что "mapM" отображает функцию в монаду ... но та, что с подчеркиванием?
@drozzy: mapM_ точно такой же, как mapM, за исключением того, что игнорирует результат. Поэтому вместо того, чтобы получать список результатов в монаде, вы просто вставляете в него (). Поскольку putStrLn в любом случае дает IO (), с mapM вы получите IO [()]; mapM_ просто превращает это в IO (), который вам действительно нужен.
Я знаю, это было какое-то время, но только что наткнулся на это. Я тоже новичок в haskell, и у меня есть вопрос. При вызове кода main просто выводит на экран содержимое dictionary.txt. Как я могу включить их в список, чтобы я мог делать другие вещи с этим списком? main имеет тип :: IO (). Как мне получить список строк, где каждая строка является строкой файла dictionary.txt? Спасибо
@Max Определенный здесь getLines :: String -> IO [String] подойдет.
Объясняя вещи кому-то, кто, кажется, все еще изучает Haskell, я бы избегал использовать (или даже показывать) бессмысленный стиль. Не хочу их пугать ;-)