Haskell:在monad transformer堆栈中替换mapM以实现惰性评估(无空间泄漏)
已经讨论过,Haskell:在monad transformer堆栈中替换mapM以实现惰性评估(无空间泄漏),haskell,monads,lazy-evaluation,monad-transformers,Haskell,Monads,Lazy Evaluation,Monad Transformers,已经讨论过,mapM本质上不是懒惰的,例如和。现在我正在努力解决这个问题的一个变体,其中所讨论的mapM位于monad转换器堆栈的深处 下面是一个函数,它取自一个使用LevelDB的具体工作(但空间泄漏)示例: 一种解决方案是使用流媒体库,如管道,管道,等等。但这些库似乎相当繁重,我根本不知道在这种情况下如何使用它们 我研究的另一个路径是所建议的ListT。但是ListT.fromFoldable::[Bool]->ListT-Bool和ListT.fold::(r->a->mr->tma->m
mapM
本质上不是懒惰的,例如和。现在我正在努力解决这个问题的一个变体,其中所讨论的mapM
位于monad转换器堆栈的深处
下面是一个函数,它取自一个使用LevelDB的具体工作(但空间泄漏)示例:
一种解决方案是使用流媒体库,如管道
,管道
,等等。但这些库似乎相当繁重,我根本不知道在这种情况下如何使用它们
我研究的另一个路径是所建议的ListT
。但是ListT.fromFoldable::[Bool]->ListT-Bool
和ListT.fold::(r->a->mr->tma->mr
(其中m
=IO
和a
,r
=Bool
)的类型签名与当前问题不匹配
什么是消除空间泄漏的“好”方法
更新:请注意,此问题与monad transformer堆栈无关!以下是建议解决方案的摘要:
1) 使用流媒体
:
import Streaming
import qualified Streaming.Prelude as S
S.all_ id (S.mapM check' (S.each [1..n]))
2) 使用Control.Monad.foldM
:
foldM (\a i-> do {b<-check' i; return $! a && b}) True [1..n]
我知道您提到您不想使用流媒体库,但是您的问题似乎很容易解决,而且代码也没有太多更改
import Streaming
import qualified Streaming.Prelude as S
我们使用每个[1..n]
而不是[1..n]
来获得元素流:
each :: (Monad m, Foldable f) => f a -> Stream (Of a) m ()
流式处理纯可折叠容器的元素
(我们也可以编写类似于S.take n$S.enumfrom1
)的代码
我们使用而不是mapmcheck'
:
mapM :: Monad m => (a -> m b) -> Stream (Of a) m r -> Stream (Of b) m r
用一元操作的结果替换流的每个元素
然后我们用以下方法来折叠布尔语流:
总而言之:
S.all_ id (S.mapM check' (S.each [1..n]))
与您开始使用的代码没有太大区别,并且不需要任何新的操作员。我知道您提到您不想使用流媒体库,但您的问题似乎很容易解决,无需对代码进行太多更改
import Streaming
import qualified Streaming.Prelude as S
我们使用每个[1..n]
而不是[1..n]
来获得元素流:
each :: (Monad m, Foldable f) => f a -> Stream (Of a) m ()
流式处理纯可折叠容器的元素
(我们也可以编写类似于S.take n$S.enumfrom1
)的代码
我们使用而不是mapmcheck'
:
mapM :: Monad m => (a -> m b) -> Stream (Of a) m r -> Stream (Of b) m r
用一元操作的结果替换流的每个元素
然后我们用以下方法来折叠布尔语流:
总而言之:
S.all_ id (S.mapM check' (S.each [1..n]))
与您开始使用的代码没有太大区别,并且不需要任何新操作符。我认为您需要的是monad loops包
然后就是allM-check'[1..n]
(或者,如果您不想导入,那么复制它是一个非常小的函数。)我认为您需要的是monad loops包
然后就是allM-check'[1..n]
(或者,如果您不想导入,那么复制它是一个非常小的函数。)除了我给出的答案之外,如果您使用
控件中的普通正则foldM
,会发生什么?似乎您也可以避免以这种方式具体化列表。我只是在这里尝试:foldM(\a I->do{b@mcmayer,请尝试使用返回$!a&&b
(当前foldM
在计算前返回类似(…&&True)&&True)&&True的thunk)。如果这不能解决问题,我想你可能是误判了泄漏。@luqui是的,return$!a&&b
确实有效!没有空间泄漏。除了我给出的答案之外,如果你使用Control.Monad
中的普通的foldM
,会发生什么?似乎你也可以避免以这种方式实现列表。我刚刚尝试了这个回复:foldM(\a i->do{b@mcmayer,请尝试使用返回$!a&&b
(当前foldM
在计算前返回类似(…&&True)&&True)&&True的thunk)。如果这不能解决问题,我想你可能是误判了泄漏。@luqui是的,返回$!a&&b
确实有效!没有空间泄漏。是的,这样做了!是的,这样做了!这是迄今为止最简单的解决方案!这是迄今为止最简单的解决方案!