【发布时间】:2014-11-03 03:22:30
【问题描述】:
所以我们有:
import Control.Monad.Writer.Strict
type M a = Writer (Map Key Val) a
对于一些Key 和Val。
只要我们不查看收集的输出,一切正常:
report comp = do
let (a,w) = runWriter comp
putStrLn a
但是,如果我们要检查 w,就会出现堆栈溢出。
report comp = do
let (a,w) = runWriter comp
guard (not $ null w) $ do -- forcing w causes a stack overflow
reportOutputs w
putStrLn a
我认为原因是因为(>>=) for Writer is defined as:
m >>= k = WriterT $ do
(a, w) <- runWriterT m
(b, w') <- runWriterT (k a)
return (b, w `mappend` w')
如果我有一个大的Writer a 计算,它会建立一个很长的mappends 序列:w <> (w' <> (w'' <> ...)),在这种情况下,这是一个Map.union,它在地图的脊椎中是严格的。因此,如果我建立了大量的联合,则必须在我强制 Map 溢出堆栈时立即评估整个事情。
我们想要的是尽早执行联合。我们想要一个更严格的 Strict.Writer:
m >>= k = WriterT $ do
(a, w) <- runWriterT m
(b, w') <- runWriterT (k a)
let w'' = w `mappend` w'
w'' `seq` return (b, w'')
所以我的问题是:这是否存在于某些“标准”库中?如果没有,为什么不呢?
【问题讨论】:
-
这在Space leak in Pipes with RWST 中已经遇到过,但是我没有关于“标准库”问题的答案。 “为什么不”可能太自以为是了。
-
好吧,“为什么不”主要是期待诸如“它不在图书馆中,因为当你把它变得过于严格时你违反了单子法则”或一些类似的技术原因。不像“因为[意见]”。
标签: haskell lazy-evaluation monad-transformers strictness