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