【发布时间】:2015-09-09 21:51:43
【问题描述】:
假设代码
f :: IO [Int]
f = f >>= return . (0 :)
g :: IO [Int]
g = f >>= return . take 3
当我在 ghci 中运行 g 时,它会导致 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 条目,则甚至不必构造列表的其余部分。而且我感觉这是不可能的:/。
【问题讨论】:
-
h'是否呼叫h?你能告诉我们真正的代码吗?您是否希望它只执行足够的IO来产生所需的结果,还是应该无论如何都执行它? -
只是为了产生所需的结果,实际代码要大得多,也更混乱,我仍然相信我在粘贴简化版本时会有所帮助。
h不是从h'调用的 -
我犯错了,我应该睡在这上面。
-
啊,好吧,如果你想通过评估来推动执行,
unsafeInterleaveIO是你唯一的选择。
标签: haskell lazy-evaluation io-monad