假设代码
f :: IO [Int]
f = f >>= return . (0 :)
g :: IO [Int]
g = f >>= return . take 3
当我g
在 ghci 中运行时,它会导致 stackoverflow。但我在想也许它可以被懒惰地评估并[0, 0, 0]
用IO
. 我怀疑IO
是这里的罪魁祸首,但我真的不知道。显然,以下工作:
f' :: [Int]
f' = 0 : f'
g' :: [Int]
g' = take 3 f'
编辑:事实上我对拥有这么简单的功能不感兴趣f
,原始代码看起来更像是:
h :: a -> IO [Either b c]
h a = do
(r, a') <- h' a
case r of
x@(Left _) -> h a' >>= return . (x :)
y@(Right _) -> return [y]
h' :: IO (Either b c, a)
-- something non trivial
main :: IO ()
main = mapM_ print . take 3 =<< h a
h
进行一些IO
计算并将无效 ( Left
) 响应存储在列表中,直到产生有效响应 ( Right
)。尝试是懒惰地构造列表,即使我们在IO
monad 中。这样阅读结果的人h
甚至可以在列表完成之前开始使用它(因为它甚至可能是无限的)。如果读取结果的人无论如何只关心第一个3
条目,则甚至不必构建列表的其余部分。而且我感觉这是不可能的:/。