mapM
は本質的に怠惰ではないことがすでに議論されています。 hereおよびhere。今私は問題のmapM
がモナド変圧器スタックの深いところにあるこの問題のバリエーションに苦しんでいます。Haskell:怠惰な評価を達成するために、モナドトランススタックでmapMを置き換えてください(スペースリークはありません)。
ここで私はgist.github.comに置くことをLevelDBを使用したコンクリートから撮影機能、作業(しかしスペース漏れ)の例です:
-- read keys [1..n] from db at DirName and check that the values are correct
doRead :: FilePath -> Int -> IO()
doRead dirName n = do
success <- runResourceT $ do
db <- open dirName defaultOptions{ cacheSize= 2048 }
let check' = check db def in -- is an Int -> ResourceT IO Bool
and <$> mapM check' [1..n] -- space leak !!!
putStrLn $ if success then "OK" else "Fail"
この関数は、彼らがすべてであることをキー[1..n]
とチェックに対応する値を読み込みます正しい。 ResourceT IO a
モナド内部の面倒ラインは
and <$> mapM check' [1..n]
一つの解決策は、これらはかなり重いように見えるなどpipes
、conduit
、としてではなく、ストリーミングライブラリを使用することであろうと私は、このすべてでそれらを使用するかどうかはわかりません状況。
私が調べたもう1つのパスはListT
です(推奨here)。しかし、タイプシグネチャListT.fromFoldable :: [Bool]->ListT Bool
とListT.fold :: (r -> a -> m r) -> r -> t m a -> mr
(m
= IO
とa
,r
= Bool
)は、手元の問題と一致しません。
スペースリークを解消するにはどうすればいいですか?
更新:この問題は、モナドトランススタックとは関係ありません。
1)Streaming
を使用する:ここで提案されたソリューションの概要です
import Streaming
import qualified Streaming.Prelude as S
S.all_ id (S.mapM check' (S.each [1..n]))
2)Control.Monad.foldM
使用:Control.Monad.Loops.allM
allM check' [1..n]
私が与えた答えのほかに、あなたはプレーン定期的に使用した場合に何が起こりますか ' 「Control.Monad」から「foldM」ですか?あなたはそのようにリストをマテリアライズすることを避けることができるようです。 – danidiaz
私はこれをここで試しました: 'foldM(\ a i-> do {b <-check 'i; return a $ && b})True [1..n]'。 'foldM' =' foldlM'も '> ='のシーケンスです。 – mcmayer
@mcmayer、 'return $! (現在は 'foldM'は評価の前に'((... && True)&& True)&& True'のようなサンクを返しています)。それで解決できない場合は、おそらく漏れを誤診していると思います。 – luqui