私はhaskellで少し実験を試みており、怠惰を利用してIOを処理することが可能かどうか疑問に思っています。文字列(文字のリスト)を受け取り、文字列を生成する関数を怠惰に作成したいと思います。それでは、IOから文字を怠惰にフィードして、各文字が利用可能になり次第処理され、必要な文字が利用可能になったときに出力が生成されるようにしたいと思います。ただし、IOモナド内の入力から文字の遅延リストを作成できるかどうか/どのように作成できるかはよくわかりません。
3 に答える
Haskellの通常の文字列IOは怠惰です。したがって、例は箱から出してすぐに機能するはずです。
次に、「interact」関数を使用した例を示します。この関数は、文字の遅延ストリームに関数を適用します。
interact :: (String -> String) -> IO ()
入力ストリームから文字「e」をゆっくりと除外してみましょう(つまり、一定のスペースで実行します)。
main = interact $ filter (/= 'e')
必要に応じて、getContentsとputStrを使用することもできます。それらはすべて怠惰です。
これを実行して、辞書から文字「e」をフィルタリングします。
$ ghc -O2 --make A.hs
$ ./A +RTS -s < /usr/share/dict/words
...
2 MB total memory in use (0 MB lost due to fragmentation)
...
したがって、2Mの一定のフットプリントで実行されたことがわかります。
怠惰なIOを実行する最も簡単な方法には、 donsが言うようinteract
にreadFile
、、、hGetContents
などの関数が含まれます。Real World Haskellの本には、これらについてさらに詳しく説明されているので、役立つかもしれません。メモリが私に役立つ場合、そのようなすべての関数は、最終的にはそのephemientが言及するものを使用して実装されるため、必要に応じて独自の関数をそのように構築することもできます。unsafeInterleaveIO
一方で、それがunsafeInterleaveIO
缶に書かれていることとまったく同じであることに注意するのが賢明かもしれません:安全でないIO。それを使用するか、またはそれに基づいて機能することで、純度と参照透過性が損なわれます。これにより、明らかに純粋な関数(つまり、IO
アクションを返さない関数)が評価されたときに外界に影響を与え、同じ引数から異なる結果を生成し、その他すべての不快なものを生成できます。実際には、最も賢明な使用方法ではunsafeInterleaveIO
問題は発生せず、単純な間違いは通常、明白で簡単に診断できるバグになりますが、いくつかの優れた保証が失われます。
もちろん、別の方法もあります。Hackageには、制限された、より安全なレイジーIOまたは概念的に異なるアプローチを提供するさまざまなライブラリがあります。しかし、実際の使用では問題が発生することはめったにないことを考えると、ほとんどの人は組み込みの技術的に危険な機能に固執する傾向があると思います。
unsafeInterleaveIO :: IO a -> IO a
unsafeInterleaveIO
怠惰に延期されるallosIO
計算。IO a
タイプの値が渡されると、の値が要求IO
された場合にのみ実行されます。a
これは、遅延ファイル読み取りを実装するために使用されます。を参照してくださいSystem.IO.hGetContents
。
たとえば、main = getContents >>= return . map Data.Char.toUpper >>= putStr
怠惰です。stdinに文字をフィードすると、stdoutに文字が表示されます。
main = interact $ map Data.Char.toUpper
(これは、ドンの答えのように、書くことと同じです。)