7

私は一般的に反応性バナナとFRPに慣れていないので、明らかな何かが欠けている場合はお詫びします。

私のプロジェクトGDB / MIフロントエンド)では、GUIとフロントエンドロジックモジュールの両方にリアクティブバナナ(バージョン0.6.0.0)を使用しています。前者はうまく機能しますが、後者の場合は明らかに追加のコンビネータが必要です。

それらの1つはですzipE :: Event t a -> Event t b -> Event t (a, b)。残念ながら、私が思いつくことができるのはchanges、イベントタイプでジェネリックではなくを使用するNetworkDescriptionモナドのソリューションだけです。

zipE :: Event t Int -> Event t String -> NetworkDescription t (Event t (Int, String))
zipE ea eb = changes $ (,) <$> stepper 0 ea <*> stepper "" eb

もちろん、私はこれに満足していません。したがって、使用せずに汎用zipE関数を実装する方法を尋ねたかったのchangesです(これは、GUI以外の目的で使用することはお勧めしません)。

他の試みは失敗しました、例えば

zipE :: Num a => Event t a -> Event t b -> Event t (a,b)
zipE ea eb = apply (stepper (0,) ((,) <$> ea)) eb

その結果、タプルの最初の要素が1つシフトします。これは、によって導入された「わずかな遅延」が原因だと思いstepperます。stepperしかし、 (またはそのことについては)イベントから動作を取得する方法がわかりaccumBません。また、動作のないイベントに関数を適用する方法もわかりません。そして全体として、ジェネリック型の場合にステッパーに初期値を提供する方法がわかりません。

4

1 に答える 1

13

zipEセマンティックに意味がないため、定義するのが困難です。セマンティック定義を検討する場合

Event a == [(Time, a)]
Event b == [(Time, b)]

一般に、各イベントは異なる時間に行われるため、それらを圧縮する自然な方法はありません。

製品の代わりに合計を使用してそれらを圧縮することが可能です。

zipE :: Event a -> Event b -> Event (Either a b)
zipE aE bE = (Left <$> aE) `mappend` (Right <$> bE)

a本当に両方をb同時に持つ必要がある場合、適切な解決策はBehavior、どちらか一方、または上記のようにマージされたEitherストリームの上に蓄積するを作成することです。

編集:マージされたストリーム(テストされていない)に蓄積する1つの方法の例。他の実装も可能です。これにより、両方のイベントが同時に発生するわけではなく、現在の状態と過去の状態を組み合わせることができるため、常に最新の両方LeftRight値を使用できます。

currentAandB :: a -> b -> Event a -> Event b -> Event (a,b)
currentAandB a0 b0 aE bE = accumE (a0,b0) (mergefn <$> zipE aE bE)
    where
        mergefn (Left a)  (_,b) = (a,b)
        mergefn (Right b) (a,_) = (a,b)

Eventそれでも、両方のストリームの初期値を提供する必要があります。このように考えてください。からEvent aのイベントしかなかった場合、タプルの2番目の部分にはどのような値が必要ですか?

于 2012-07-31T15:01:08.117 に答える