【发布时间】:2021-06-12 17:35:54
【问题描述】:
我尝试编写一个程序,它将文件路径作为(命令行)参数并返回每个文件的第一行
main = getArgs >>= ( mapM_ ( \file -> ( openFile file ReadMode >>= ( (\handle -> hGetLine handle >>= print) >> hClose ) ) ) )
我知道这看起来不太漂亮,但我只是 Haskell 的初学者。我也故意避免使用 do 表示法,因为我(还)对她感觉不太舒服。
因此,上面的代码编译并返回无效文件路径的错误,而对于有效路径则没有任何内容(即尤其不是文件的第一行)。
我必须承认我几乎不知道我做错了什么,但我做了以下观察:
如果我添加以下内容来检查哪些部分仍然被执行
main = getArgs >>= ( mapM_ ( \file -> ( openFile file ReadMode >>= ( (\handle -> hGetLine handle >>= print) >> (const $ putStr "Hello1") >> hClose >> (const $ putStr "Hello2") ) ) ) )
程序只打印第二个“Hello”,这让我想起了 (>>) 的类型签名:
(>>) :: Monad m => m a -> m b -> m b
所以考虑到只有第二个参数类型的东西被返回,也许第一个参数被忽略了?
但是反对这个理论的第一个论点是这样的函数似乎不是很有用(至少在 IO Monad 的上下文中不是),第二个是程序
main = (putStr "Hello" >> putStr "World" >> putStr "!")
返回“HelloWorld!”正如预期的那样。因此,我一定是完全走错了路,这就是我来这里的原因。
感谢您的帮助!
【问题讨论】:
-
>>只返回正确的结果,但它会执行 both effects - 你应该很好 - 你可以添加关于如何调用程序以及错误到底是什么的示例?也许文件确实不存在或找不到? -
顺便说一句:你真的应该试着把它翻译成
do- 它应该是直截了当的(应该看起来像你在命令式语言中所期望的那样) - 在这里(对我来说)很难解析为这一切都与(,,)和滚动条一致;) -
@Carsten '关于如何调用程序以及错误到底是什么的示例':“./Main file.txt”返回“”,“./Main file_notExistent.txt”返回“Main :file_notExistent.txt:openFile:不存在(没有这样的文件或目录)”。所以问题不是包含在错误消息中,而是缺少任何消息。关于 do 符号:我的问题是我总是必须先将符号转换回显式符号才能理解它。首先是硬逻辑,然后是漂亮的符号,至少这是我学得最好的方式。
-
正如我在下面写的那样,您的问题实际上是您没有将
hClose放在正确的位置-这样>>用于(->)Monad 而不是IO-所以它确实将handle传递给hGetLine handle >>= print和hClose但>>忽略了第一个结果IO结果,只返回了hClose一个 - 所以这里的效果是通过handle和结果只是关闭了文件——是的,它很微妙而且不明显,因为你很少看到/想到 reader-monad 实例(这里是(->) handle的 Monad 实例) -
我同意这对于新的(甚至是经验丰富的)Haskellers 来说可能真的很令人费解,为什么这不会在这里导致类型错误并且实际上在运行时会做一些事情......
->functor、monad 等的实例很好,但可能对初学者不太友好
标签: haskell