e1 :: Event t A
f :: A -> IO B
は私がe1
によってトリガされる
e2 :: Event t B
を作成する必要があり、かつその値はイベント発生時にe1
の値にf
を実行することによって決定されているとしましょう。
ダイナミックイベントの切り替えとハンドラの使用による2つの可能性がある方法がありますが、そのような単純なことはどちらも複雑すぎます。
これを行う適切な方法は何ですか?
e1 :: Event t A
f :: A -> IO B
は私がe1
によってトリガされる
e2 :: Event t B
を作成する必要があり、かつその値はイベント発生時にe1
の値にf
を実行することによって決定されているとしましょう。
ダイナミックイベントの切り替えとハンドラの使用による2つの可能性がある方法がありますが、そのような単純なことはどちらも複雑すぎます。
これを行う適切な方法は何ですか?
機能f
には副作用があるため、実際には簡単なことではありません。主な理由は、副作用の順序が複数の同時イベントがある場合には明確に定義されていないことです。より一般的には、イベントでIOアクションを処理するための良いセマンティクスを考えることができませんでした。したがって、反応性バナナは、この状況に対して純粋なコンビネータを提供しません。
これをやりたければ、副作用の順番を決定する、より精巧なメカニズムを使用する必要があります。たとえば、あなたはreactimate
を使用してコンビネータ
mapIO :: Frameworks t => (a -> IO b) -> Event t a -> Moment t (Event t b)
mapIO f e1 = do
(e2, fire2) <- liftIO newAddHandler
reactimate $ (\x -> f x >>= fire2) <$> e1
fromAddHandler e2
を書くことができますしかし、結果イベントe2
は、もはや入力イベントe1
と同時であるとして、これは予期しない結果が得られないかもしれないことに注意してください。たとえば、動作が変更され、その他の副作用が実行されている可能性があります。
FRPの目的はIOを扱うことであるから、IOアクションは「ファーストクラス」ではないという点で、少し驚くべきことです。 特に、同時イベントには順序があります - それで、対応するエフェクトに同じ順序を使用しないのはなぜですか? 私はこれが強打ではないことを理解します。 IOアクションは他のイベントを引き起こす可能性があり、イベントを「同時」とみなすには時間がかかりすぎます...しかし、私はその責任を負うことができます。つまり、私はイベントハンドラを呼び出さないことを約束し、そのアクションは私の目的にとって「瞬間的」になるでしょう。それはまだ不可能ですか?どうして? –
まあ、同時のイベントはすべてのイベントでオーダーを持つかもしれませんが、グローバルオーダーはありません。 'ex'と' ey'が同時に発生する 'union ex ey'と' union ey ex'の2つのイベントを考えてみましょう。プログラムは同時に両方の組み合わせをうまく使用することができますが、同時に発生するイベントの順序はそれぞれ異なります。より一般的には、イベントでIOアクションを注文するための良いセマンティクスを見つけることができなかったため、反応性バナナはそれらをサポートしていません。 (私はこの点を強調するために私の答えを更新しました) –
一般的にFRPについては、これが失望していないことを願っていますが、IOはあまりIOではなく、事象や時変値で計算することに焦点を当てています。つまり、あなたはしばしば境界でIOとインターフェースする必要があります。多くの可能性があります: 'reactimate'または' mapIO'コンビネーター、 'Reactive.Banana.Frameworks 'の' mapIO'コンビネーター。AddHandler'モジュールを使用してイベントを修正してからFRPワールドに渡すことができます。 –
f
をreactimate
(これはイベントネットワークからIOを処理する「適切な方法」と理解しています)で呼び出すことができますか?そこで、イベントネットワークにタイプEvent t B
の新しいイベントを発生させます。または、これはあなたが「ハンドラを使用する」という意味ですか?
はい、それは私が「ハンドラを使う」という意味です。 –
は 'unsafePerformIO'オプションですか? – Ankur
@Ankur:いいえ、それは間違いなく「適切な方法」ではありません。 –