【问题标题】:How to use readFile如何使用读取文件
【发布时间】:2017-10-15 17:30:31
【问题描述】:

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

如果我理解正确,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

【问题讨论】:

  • “如果我理解正确, do 语句应该将字符串从 Monad 中拉出。”不完全的。你之前在 Haskell 中做过 IO 吗?
  • 不,这是我第一次处理 IO 和 Monads。我一直在研究learnyouahaskell.com 的示例。我已经通读了这本书。
  • 非常粗略地说,do x &lt;- action ; ... 确实将x 拉出 IO action,但如果后续的 ... 仍在 IO 内部工作,那么最终返回类型为IO something 形式。没有办法只“删除 IO”——这是因为,按照设计,我们希望 IO 出现在任何执行 IO 的函数的返回类型中。这就是重点!您可以阅读monads in picutres 了解更多示例。

标签: haskell io monads


【解决方案1】:

您无法从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]

你应该能够克服第一个障碍。

【讨论】:

  • 我不认为do { fileContent &lt;- readFile f; map ... } 应该工作;它需要在map 周围加上return 或一些类似的更改。
  • @DanielWagner 是的,你是对的。谢谢你的纠正。我承认我没有尝试编译代码,因为OP中的代码不完整。
【解决方案2】:

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

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[] 统一起来。你真正想要的是返回这个值:

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

现在回想一下,我们永远不能“退出”你的readLevelFile 类型必须是 IO 的 IO monad - 诚实地承认它与外部世界交互:

readLevelFile :: FilePath -> IO [FallingRegion]

【讨论】:

    猜你喜欢
    • 2018-01-06
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    • 2015-03-05
    • 2015-07-31
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    相关资源
    最近更新 更多