我在Haskell中读取级别文件时遇到问题。目标是读取一个简单的txt文件,其中两个数字用空格分隔,然后用逗号分隔。我一直遇到的问题是:无法匹配类型`IO' with `[]'
如果我理解正确,那么do语句应该将String拉出Monad。
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
答案 0 :(得分: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]
你应该能够超越第一道障碍。
答案 1 :(得分:1)
让我们看一下显式类型的第一个函数:
readLevelFile f = do
(fileContent :: String) <-
(readFile :: String -> IO String) (f :: String) :: IO String
fileContent
确实属于String
类型,但仅在我们正在评估的IO Monad执行期间可用。现在怎么样?
(map lineToFallingRegion (lines fileContent)) :: [String]
现在您突然使用的表达式不是IO
monad,而是列表值 - 因为列表也是monad类型,类型检查尝试将IO
与{{1}统一起来}}。你真正想要的是返回这个值:
[]
现在回想起我们不能“退出”你的return (map lineToFallingRegion (lines fileContent)) :: IO [String]
类型必须是IO的IO monad - 诚实地承认它与外部世界的互动:
readLevelFile