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