【发布时间】:2014-06-06 01:49:00
【问题描述】:
我一直在尝试严格和懒惰的ST monads,我并不清楚每个人的懒惰程度。
例如,使用惰性 Control.Monad.State.Lazy monad 我们可以这样写:
main = print $ (flip evalState) "a" $ do
forever $ put "b"
put "c"
get
这工作正常并输出"c"。双重的,严格的Control.Monad.State.Strict 变体的相同代码将永远运行put "b",然后挂起。
直觉上,我希望ST monads 具有相同的二元性。也就是说,给定代码:
main = print $ S.runST $ do
r <- newSTRef "a"
forever $ writeSTRef r "b"
writeSTRef r "c"
readSTRef r
Control.Monad.ST.Lazy 应该输出"c",而Control.Monad.ST.Strict 应该挂起。但是,它们都无限循环。我相信这是有正当理由的,例如:向后阅读,在调用最后一个writeSTRef 时尚未分配引用r。但不知何故,感觉我们可以做得更好。
【问题讨论】:
-
您可以使用
Control.Monad.Lazy.Unsafe.unsafeInterleaveST $ forever $ writeSTRef r "b"来获得您正在寻找的懒惰。不过,在不了解您的问题的情况下,我不能说这样做是否真的安全。 -
是的,这就是我找到的解决方案。 @luqui 也在 [stackoverflow.com/questions/24068399/… 线程上对此发表评论。
forever有点夸张,因为您似乎至少需要追溯修改的历史(而不是在我希望的相同参考上评估修改的历史)到创建点。 -
哦,我应该指出
unsafeInterleaveST意味着推迟对其参数的评估,直到需要结果值。这意味着如果您忽略unsafeInterleaveST的结果(如我的评论中所述),您也可以删除该行。unsafeInterleave*函数真正用于创建列表等辅助数据。
标签: haskell