Haskell 如何使用readFile

Haskell 如何使用readFile,haskell,io,monads,Haskell,Io,Monads,我在Haskell中读取级别文件时遇到问题。目标是读取一个简单的txt文件,其中两个数字用空格分隔,然后用逗号分隔。我一直遇到的问题是:无法将类型`IO'与“[]”匹配 如果我理解正确,do语句应该将字符串从Monad中拉出 readLevelFile :: FilePath -> [FallingRegion] readLevelFile f = do fileContent <- readFile f (map lineToFallingRegi

我在Haskell中读取级别文件时遇到问题。目标是读取一个简单的txt文件,其中两个数字用空格分隔,然后用逗号分隔。我一直遇到的问题是:无法将类型
`IO'与“[]”匹配


如果我理解正确,do语句应该将字符串从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
readLevelFile::FilePath->[FallingRegion]
readLevelFile f=do
fileContent FallingRegion
lineToFallingRegion s=映射文本ShapeToFallingShape(拆分“(==”,“)s)
textShapeToFallingShape::String->FallingShape
textShapeToFallingShape s=FallingShape(读取$head编号)(读取$head
$尾号)
其中数字=splitOn'(='')s

让我们看看第一个显式类型的函数:

readLevelFile f = do
    (fileContent :: String) <-
                  (readFile :: String -> IO String) (f :: String) :: IO String
现在您突然使用的表达式不是
IO
monad,而是列表值-由于列表也是monad的一种类型,因此类型检查尝试将
IO
[]
统一起来。您实际想要的是返回此值:

return (map lineToFallingRegion (lines fileContent)) :: IO [String]
现在回想一下,我们不能“退出”IO monad,您的
readLevelFile
类型必须是IO-诚实地承认它与外部世界交互:

readLevelFile :: FilePath -> IO [FallingRegion]

您无法从
IO
中提取内容。你可以把
IO
想象成一个容器(事实上,对
IO
的一些解释把它比作一个装有薛定谔猫的盒子)。您看不到容器中的内容,但如果您进入容器,值将可见

因此,这应该是可行的:

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

您应该能够越过第一个障碍。

“如果我理解正确,do语句应该能够将字符串从单子中拉出。”不完全正确。你以前在Haskell做过IO吗?没有,这是我第一次处理IO和Monads。我一直在从中学习示例。我已经通读了这本书。非常粗略地说,
do x我不认为
do{fileContent@DanielWagner是的,你是对的。谢谢你的更正。我承认我没有尝试编译代码,因为OP中的代码不完整。
readLevelFile f = do
    fileContent <-  readFile f
    return (map lineToFallingRegion (lines fileContent))
readLevelFile :: FilePath -> IO [FallingRegion]