[英]A Stricter Control.Monad.Trans.Writer.Strict
所以我們有:
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
計算,它會構建一個很長的mappend序列: 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'')
所以我的問題是:這是否存在於某些“標准”庫中? 如果沒有,為什么不呢?
您問題的直接答案是:不,沒有標准庫提供此功能。 此外,您提出的版本仍將泄露。 我知道,不漏的唯一版本是模擬WriterT
使用嚴格StateT
。 我在Haskell庫郵件列表中寫了一篇非常詳細的電子郵件,比較了幾個實現的嚴格性和性能。 簡而言之:將WriterT
作為嚴格的StateT
實現,不僅可以消除空間泄漏,還可以生成非常高效的代碼。
這是有效的實現:
newtype WriterT w m a = WriterT { unWriterT :: w -> m (a, w) }
instance (Monad m, Monoid w) => Monad (WriterT w m) where
return a = WriterT $ \w -> return (a, w)
m >>= f = WriterT $ \w -> do
(a, w') <- unWriterT m w
unWriterT (f a) w'
runWriterT :: (Monoid w) => WriterT w m a -> m (a, w)
runWriterT m = unWriterT m mempty
tell :: (Monad m, Monoid w) => w -> WriterT w m ()
tell w = WriterT $ \w' ->
let wt = w `mappend` w'
in wt `seq` return ((), w `mappend` w')
我想在某些時候看到這個添加到transformers
中,但是有一些小問題需要解決(例如,模塊名稱應該是什么)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.