我还在开始探索Haskell。我知道这段代码在IO
monad中“运行”。当它从l <- ...
行转到下一行时,会调用IO - bind
。
有人可能会认为,因为Haskell lazy ,所以永远不会评估l
。但是“bind
”总是评估上一个命令,是吗?因为程序产生“文件未找到”错误。
main = do
l <- mapM readFile [ "/tmp/notfound" ]
return ()
答案 0 :(得分:15)
有人可能会认为,因为Haskell是懒惰的,所以l永远不会被评估。
是的,它永远不会被评估。但是,由于(>>=)
中IO
的定义,将执行操作readFile "/tmp/notfound"
,这意味着运行时会尝试打开该文件。如果没有此类文件,则会引发“找不到文件”错误。如果有这样的文件,它将被打开,但是在要求之前不会读取其内容。在上面,不要求它们,因此不会读取内容。
在此处评估(甚至执行)是生成l
的动作。由于该文件不存在,因此会引发错误。
答案 1 :(得分:9)
如果您在代码中展开do
表示法,则会得到:
main = (mapM readFile ["/tmp/notfound"]) >>= (\l -> return ())
所以是的,l
永远不会被评估,但这并不意味着永远不会评估对mapM
的调用。 >>=
始终需要评估其左操作数,以便至少在某种程度上产生一个值(至少在IO monad和任何其他想象的monad中)。