3

我最近读到了Writer/ WriterTmonad 的空间泄漏问题。如果我正确理解了这个问题,那是因为绑定运算符,即(>>=)不是尾递归:

m >>= f = WriterT $ do
    (a, w1) <- runWriterT m
    (b, w2) <- runWriterT (f a)
    return (b, w1 `mappend` w2)

定义WriterTWriter

newtype WriterT w m a = WriterT { runWriterT :: m (a, w) }
type Writer w = WriterT w Identity

我很好奇在第二个参数上引入惰性是否mappend会解决这个空间泄漏问题。

通过引入惰性,我的​​意思是类似于(++)运算符:

(++) :: [a] -> [a] -> [a]
(++) []     ys = ys
(++) (x:xs) ys = x : (xs ++ ys)

结果是在没有实际接触第二个参数的情况下产生的。

现在,如果我们使用m带有惰性单子绑定的单子(例如m ~ Identity,它给了我们普通的旧Writer单子),并使用mappend上面提到的,那么f a部分 ( w2) 在评估时可以保持 thunk mappend w1 w2,因此结果可以部分消耗 ( w1) 而没有实际上强制其余表达式(w2)。

我对此是否正确?Writer在这样的monad中是否避免了空间泄漏?

4

0 回答 0