簡體   English   中英

一個更嚴格的Control.Monad.Trans.Writer.Strict

[英]A Stricter Control.Monad.Trans.Writer.Strict

所以我們有:

import Control.Monad.Writer.Strict

type M a = Writer (Map Key Val) a

對於一些KeyVal

只要我們不查看收集的輸出,一切都可以正常工作:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM