MAPM

2012-09-26 4 views
11
の怠惰なバージョン

と仮定、私はアイテムの大規模なリストを取得しています:MAPM

as <- getLargeList 

は今、私はasfn :: a -> IO bを適用しようとしている:

as <- getLargeList 
bs <- mapM fn as 

mapMましたmapM :: Monad m => (a -> m b) -> [a] -> m [b]と入力してください。これがタイプマッチングの観点から必要なものです。しかし、結果を返すまでメモリ内のすべてのチェーンを構築します。私はmapMのアナログを探しています。遅れても動作しますので、tailがまだ構築されている間に私はbsの頭を使うかもしれません。

+1

おそらくこれが役立ちます。 http://stackoverflow.com/questions/3270255/is-haskells-mapm-not-lazy –

+0

Anton、私はこのトピックを読んだが、私は答えを見つけられなかった:怠惰な計算のためのmapMの代替があるかどうか。 –

+0

@DmitryBespalov同じ型の署名ではありません。 'Monad'は、後でそれを延期するための抽象概念を持っていません。それが' mapM'がレイジーになるためにはあなたがしなければならないことです。 – Carl

答えて

18

unsafeInterleaveIOや遅延IOを使用しないでください。これは正確には、反復子が予測できないリソース管理をもたらす遅延IOを回避するために作成された問題です。トリックはになり、リストは決して作成されず、イテレートを使用してストリームされます。これを実証するために、私自身のライブラリpipesの例を使用します。

まず、定義:それを実行してみましょう、

prompt100 :: Producer Int IO() 
prompt100 = replicateM_ 1000 $ do 
    lift $ putStrLn "Enter an integer: " 
    n <- lift readLn 
    yield n 

>>> runPipe $ printer <+< take' 1 <+< prompt100 
Enter an integer: 
3<Enter> 
3 

import Control.Monad 
import Control.Monad.Trans 
import Control.Pipe 

-- Demand only 'n' elements 
take' :: (Monad m) => Int -> Pipe a a m() 
take' n = replicateM_ n $ do 
    a <- await 
    yield a 

-- Print all incoming elements 
printer :: (Show a) => Consumer a IO r 
printer = forever $ do 
    a <- await 
    lift $ print a 

を今度は、私たちのユーザーに意味し、彼らは私たちにとって本当に大きなリストを作成要求されてみましょう

我々は唯一の整数を要求するので、それは唯一、1つの整数をユーザーに要求します!

あなたはgetLargeListからの出力でprompt100を交換したい場合は、あなただけの書き込み:

yourProducer :: Producer b IO() 
yourProducer = do 
    xs <- lift getLargeList 
    mapM_ yield xs 

を...そして実行します:

>>> runPipe $ printer <+< take' 1 <+< yourProducer 

これを遅延リストをストリーミングし、構築することはありませんメモリ内にリストしてください。すべて安全ではありません。IOハックです。必要な要素の数を変更するには、渡す値を変更するだけです。take'

pipes tutorialControl.Pipe.Tutorialと読んでください。

あなたがhereを見つけることができ、対象のオレグのオリジナルのスライドを読んで、怠惰なIOは、問題が発生する理由についての詳細を学ぶために。彼は遅延IOを使って問題を説明する素晴らしい仕事をしています。あなたが遅延IOを使用するように強いられると感じるたびに、本当に必要なものはiterateeライブラリです。

+5

パイプライブラリ用の+100 –

+2

ガブリエル、答えてくれてありがとう!そして、それは本当に便利なライブラリです、ありがとう! –

+0

@DmitryBespalovようこそ。私はいつも助けてくれるのです。 –

6

IOモナドには、エフェクトを遅延させるメカニズムがあります。それはunsafeInterleaveIOと呼ばれています。

import System.IO.Unsafe 

lazyMapM :: (a -> IO b) -> [a] -> IO [b] 
lazyMapM f [] = return [] 
lazyMapM f (x:xs) = do y <- f x 
         ys <- unsafeInterleaveIO $ lazyMapM f xs 
         return (y:ys) 

これは、レイジーIOの実装方法です。効果が実際に実行される順序は予測が難しく、結果リストの要素が評価される順序によって決定されるという意味では安全ではありません。このため、fのIO効果は秩序に影響を受けないという意味では、大切です。通常、十分に害のない効果の良い例は、読み取り専用ファイルからの読み取りです。

+1

私の見解から、HaskellでSystem.IO.Unsafeを使用することは、ハックのようなものです。私はその "安全でない"動作のために使用しないことを好む。しかし、私はあなたの答えに感謝します。 –

関連する問題