Как использовать 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]