Как использовать readFile

У меня проблемы с чтением файла уровня в Haskell. Цель состоит в том, чтобы прочитать простой текстовый файл с двумя числами, разделенными пробелом, а затем запятыми. Проблема, которую я продолжаю получать, заключается в следующем: не может соответствовать типу `IO' with `[]'

Если я правильно понимаю, оператор do должен вытащить строку из монады.

readLevelFile :: FilePath -> [FallingRegion]
readLevelFile f = do
        fileContent <-  readFile f
        (map lineToFallingRegion (lines fileContent))

lineToFallingRegion :: String -> FallingRegion
lineToFallingRegion s = map textShapeToFallingShape (splitOn' (==',') s) 

textShapeToFallingShape :: String -> FallingShape
textShapeToFallingShape s = FallingShape (read $ head numbers) (read $ head 
$ tail numbers)
                      where numbers = splitOn' (==' ') s

2 ответа

Вы не можете вытащить вещи из IO, Вы можете думать о IO в качестве контейнера (на самом деле, некоторые интерпретации IO уподобьте это шкатулке, в которой находится кот Шредингера. Вы не можете видеть, что находится в контейнере, но если вы войдете в контейнер, значения станут видимыми.

Так что это должно работать:

readLevelFile f = do
    fileContent <-  readFile f
    return (map lineToFallingRegion (lines fileContent))

Однако он не имеет типа, указанного в OP. Внутри do блок, fileContent это String значение, но весь блок все еще находится внутри IO контейнер.

Это означает, что тип возвращаемого значения функции не [FallingRegion], но IO [FallingRegion], Так что если вы измените аннотацию типа для readLevelFile в

readLevelFile :: FilePath -> IO [FallingRegion]

Вы должны быть в состоянии преодолеть первое препятствие.

Давайте посмотрим на вашу первую функцию с явными типами:

readLevelFile f = do
    (fileContent :: String) <-
                  (readFile :: String -> IO String) (f :: String) :: IO String

fileContent действительно типа String но доступно только в рамках исполнения Монады IO, в соответствии с которой мы оцениваем. Что теперь?

    (map lineToFallingRegion (lines fileContent))  :: [String]

Теперь вы вдруг используете выражение, которое не является IO монада, но вместо этого является значением списка - так как списки также являются типом монады, проверка типа пытается унифицировать IO с [], На самом деле вы хотели вернуть это значение:

return (map lineToFallingRegion (lines fileContent)) :: IO [String]

Теперь вспоминая, что мы никогда не сможем "выйти" из монада вашего IO readLevelFile Тип должен быть IO - честное признание того, что он взаимодействует с внешним миром:

readLevelFile :: FilePath -> IO [FallingRegion]
Другие вопросы по тегам