11

IOを使用しているときに、大量のアイテムのリストを取得するとします。

as <- getLargeList

今、私はに適用しようとしていfn :: a -> IO bますas

as <- getLargeList
bs <- mapM fn as

mapMタイプmapM :: Monad m => (a -> m b) -> [a] -> m [b]があり、それがタイプマッチングの観点から必要なものです。ただし、結果が返されるまで、すべてのチェーンがメモリに構築されます。尾がまだ構築されている間mapMに頭を使用できるように、怠惰に動作するのアナログを探しています。bs

4

2 に答える 2

18

unsafeInterleaveIOそのことについては、または怠惰なIOを使用しないでください。これはまさに、反復が対処するために作成された問題です。つまり、予測できないリソース管理を提供する遅延IOの回避です。秘訣は、リストを作成せず、使い終わるまで反復を使用してリストを常にストリーミングすることです。これを示すために、自分のライブラリの例を使用しますpipes

まず、以下を定義します。

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

さて、私たちのユーザーに意地悪をして、彼らが私たちのために本当に大きなリストを作成することを要求しましょう:

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

1つの整数しか要求しないため、ユーザーに1つの整数の入力を求めるだけです。

prompt100からの出力に置き換えたい場合はgetLargeList、次のように記述します。

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

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

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

IOこれにより、リストが遅延ストリーミングされ、安全でないハックを使用せずに、メモリ内にリストが作成されることはありません。必要な要素の数を変更するには、渡す値を変更するだけですtake'

このような他の例については、のpipesチュートリアルをお読みくださいControl.Pipe.Tutorial

怠惰なIOが問題を引き起こす理由の詳細については、ここで見つけることができる主題に関するOlegの元のスライドをお読みください。彼は怠惰なIOの使用に関する問題を説明する素晴らしい仕事をしています。レイジーIOを使用せざるを得ないと感じるときはいつでも、本当に必要なのはiterateeライブラリです。

于 2012-09-26T20:48:28.193 に答える
7

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の実装方法です。効果が実際に実行される順序を予測するのは難しく、結果リストの要素が評価される順序によって決定されるという意味は安全ではありません。このため、のIO効果はf、順序に依存しないという意味で、良性であることが重要です。通常は十分に害のない効果の良い例は、読み取り専用ファイルからの読み取りです。

于 2012-09-26T20:26:04.673 に答える