次のHaskellプログラムを考えてみましょう。私は関数がストリーム上で動作する "ストリームスタイル"(ここでは単にリストとして実装されています)でプログラムしようとしています。 normalStreamFuncのようなものは、怠惰なリストでうまくいく。私は無限のリストをnormalStreamFuncに渡し、無限の別のリストを効果的に出すことができますが、関数は各値にマップされます。 effectfulStreamFuncのようなものはうまく動作しません。 IOアクションは、個別の値を引き出す前にリスト全体を評価する必要があることを意味します。未評価の残りのアクションを残しIO効果を伴うHaskellストリーム
a
b
"[\"a\",\"b\"]"
:プログラムはこれを生成するように
a
b
c
d
"[\"a\",\"b\"]"
が、私がしたいことはeffectfulStreamFuncを書くための方法である:例えば、プログラムの出力がこれです。私はunsafePerformIOを使用して解決策を想像することができますが、私はテーブルからそれを取っているとしましょう。ここではプログラムは次のとおりです。
import IO
normalStreamFunc :: [String] -> [String]
normalStreamFunc (x:xs) = reverse(x) : normalStreamFunc xs
effectfulStreamFunc :: [String] -> IO [String]
effectfulStreamFunc [] = return []
effectfulStreamFunc (x:xs) = do
putStrLn x
rest <- effectfulStreamFunc xs
return (reverse(x):rest)
main :: IO()
main = do
let fns = ["a", "b", "c", "d"]
es <- effectfulStreamFunc fns
print $ show $ take 2 es
更新:
が参考と思いやりのフィードバックありがとうございました。私は前にsequence
オペレータを見ていなかった、それについて知っておくと便利です。私はString(String)の代わりにIO(String)値を渡す方法はあまりエレガントではないと思っていましたが、限られた有用性を持つプログラミングスタイルのために、他のストリーム関数を文字列を生成するアクション。しかし、他の回答を通して考えてみると、なぜこれが一般的には解決できないのか分かります。私が提示した単純なケースでは、ストリームの順序付けがアクションの順序付けを暗示していると考えていたので、私が本当に望んでいたのはsequence
オペレータでした。実際、このような順序付けは必ずしも暗示されていません。これは、2つのストリームを入力として受け取るストリーム関数(例えば、ペアごとに2つのストリームを追加する)について考えると、私には明らかになります。両方の "着信"ストリームがIOを実行した場合、それらのIOアクションの順序は未定義です(もちろん、IOモナドで自分自身を順序付けして定義しない限り)。問題は解決しました、皆さんありがとう!
のように見えます。この場合
putAction = do putStrLn x return x in putAction:effectfulStreamFunc xs 少し良くなると思います。 –
良い点。私は構文が実際にモナドを実行する問題に直交していると思います。 –