所以我们有:
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
我认为原因是因为(>>=)
forWriter
被定义为:
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'')
所以我的问题是:这是否存在于某些“标准”库中?如果不是,为什么不呢?