Haskell から呼び出す C で記述された関数がいくつかあります。これらの関数は を返しIO (CInt)
ます。戻り値に関係なく、すべての関数を実行したい場合がありますが、これは簡単です。サンプルコードのために、これは現在何が起こっているかの一般的な考えです:
Prelude> let f x = print x >> return x
Prelude> mapM_ f [0..5]
0
1
2
3
4
5
Prelude>
望む副作用が得られ、結果は気にしません。しかし、ここでは、目的の結果を返さない最初の項目の直後に実行を停止する必要があります。戻り値が 4 以上の場合、実行を停止する必要があるとしましょう。その場合、私がやりたいことは次のとおりです。
Prelude> takeWhile (<4) $ mapM f [0..5]
これは私にこのエラーを与えます:
<インタラクティブ>:1:22: 予想される型 `[b]' と推測された型 `IO a' を一致させることができませんでした `mapM' の最初の引数、つまり `f' `($)' の 2 番目の引数、つまり `mapM f ([0 .. 5])' 式: takeWhile (< 4) $ mapM f ([0 .. 5])
そして、それは私には理にかなっています-結果はまだ IO モナドに含まれており、IO モナドに含まれている 2 つの値を単純に比較することはできません。これがまさにモナドの目的であることを知っています-結果を連鎖させ、特定の条件が満たされたときに操作を破棄します-しかし、この場合、IOモナドを「ラップ」して、条件でチェーンの実行を停止する簡単な方法はありますか?のインスタンスを記述せずに、私の選択のMonadPlus
?
f
takeWhileの目的で、 から値を「持ち上げる」ことはできますか?
これは、ファンクターが適合するソリューションですか? ファンクターはまだ「クリック」していませんが、これはファンクターを使用するのに良い状況かもしれないという印象を持っています。
アップデート:
@sth は私が望むものに最も近い答えを持っています - 実際、それは私が目指していたものとほぼ同じですが、明示的に再帰的でない標準的な解決策があるかどうかを知りたいです - これは Haskell です。全て!質問の言い方を振り返ってみると、自分が望んでいる行動について十分に明確ではなかったことがわかります。
上記f
の例で使用した関数は、単なる例です。実際の関数は C で記述されており、その副作用のみに使用されます。mapM_ f (takeWhile (<4) [0..5])
実行されるまで、入力が実際に成功するか失敗するかがわからないため、@Tomの提案を使用できません。
返されたリストも実際には気にしません。リストが使い果たされるか、最初の C 関数が失敗コードを返すまで、C 関数を呼び出したいだけです。
C スタイルの擬似コードでは、私の動作は次のようになります。
do {
result = function_with_side_effects(input_list[index++]);
} while (result == success && index < max_index);
繰り返しますが、@ sthの回答は、結果が破棄される可能性がある(すべきか?)ことを除いて、私が望む正確な動作を実行します。関数は私のdropWhileM_
目的と同等です。なぜそのような関数やtakeWhileM_
Control.Monad にないのですか? メーリング リストで同様の議論があったようですが、それについては何も語られていないようです。