haskell - RWST 管道中的空间泄漏

标签 haskell haskell-pipes

以下程序的内存分析表明,noleak 函数在恒定内存中运行,而leak 函数以线性方式泄漏内存。 dflemstr 表示这可能是由于 RWST 导致无限的分配链。是这种情况吗?还有其他解决方案吗?我实际上不需要 Writer monad。

环境:

ARCH 64 位上的 GHC 7.8.3

ghc Pipe.hs -o Pipe -prof

import Control.Concurrent (threadDelay)
import Control.Monad (forever)

import Pipes
import Control.Monad.Trans.RWS.Strict

main = leak

effectLeak :: Effect (RWST () () () IO) ()
effectLeak =
  (forever $ do
      liftIO . threadDelay $ 10000 * 1
      yield "Space") >->
  (forever $ do
      text <- await
      yield $ text ++ (" leak" :: String)) >->
  (forever $ do
      text <- await
      liftIO . print $ text
  )

effectNoleak :: Effect IO ()
effectNoleak =
  (forever $ do
      lift . threadDelay $ 10000 * 1
      yield "Space") >->
  (forever $ do
      text <- await
      yield $ text ++ (" leak" :: String)) >->
  (forever $ do
      text <- await
      lift . print $ text
  )

leak = (\e -> runRWST e () ()) . runEffect $ effectLeak

noleak = runEffect $ effectNoleak

最佳答案

Zeta 是对的,空间泄漏是由于 WriterT 造成的。无论您使用什么幺半群,WriterTRWST(“严格”版本和惰性版本)总是会泄漏空间。

我对此写了一个更长的解释 here ,但总结如下:不泄漏空间的唯一方法是使用 StateT monad 模拟 WriterT,其中 tell 使用严格的模拟放置,如下所示:

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 ((), wt)

这基本上相当于:

type WriterT = StateT

runWriterT m = runStateT m mempty

tell w = do
    w' <- get
    put $! mappend w w'

关于haskell - RWST 管道中的空间泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25280852/

相关文章:

postgresql - 无法在 OS X 上使用 Docker 构建 Haskell/Postgres 项目

haskell - ProxyFast/ProxyCorrect 的 MonadTransControl 实例

haskell - 如何将外部导出函数的参数传递到管道中?

haskell - Haskell 中的 int 字面量

haskell - 如何阅读haskell类型签名?

haskell - 代数类型 - Haskell

regex - Text.Regex.Posix 的=~ 运算符在某些模式下无法获取返回值

haskell - 管道教程 : ListT example

haskell - 如何检测 Haskell Pipe 中的最后一个 block ?

haskell - Pipes (Haskell lib) - 具有不同状态 monad 的管道