ZipE implementation :: Event ta & # 8594; Event tb & # 8594; Event t (a, b)

I am new to reactive banana and FRP in general, so I apologize if I am missing something obvious.

For my project ( GDB / MI ) I use reactive banana (version 0.6.0.0) for the graphical interface and the interface logic modules. The former works fine, but for the latter, I apparently need additional combinators.

One of them is zipE :: Event ta -> Event tb -> Event t (a, b) . Unfortunately, all I could think of was a solution in the NetworkDescription monad that uses changes and is not common to event types:

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

Of course, I am not satisfied with this. So, I wanted to ask how to implement the general zipE function without using changes (which is not recommended for purposes other than the GUI).

Other attempts failed, for example.

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

leads to the fact that the first elements of the tuples are shifted by one - I think, due to the "slight delay" introduced by stepper . But I don’t see how to get behavior from an event without stepper (or accumB , for that matter), and I don’t see how to apply a function to an event without behavior. And in general, I do not see how to provide the initial value of stepping in the case of the generic type.

+7
source share
1 answer

You have difficulty defining zipE because it does not make semantic meaning. If you consider semantic definitions

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

There is no natural way to zip them, because usually each event will be at a different time.

You can fix them using the amount instead of the product.

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

If you really need to have both a and b at the same time, a suitable solution is to create a Behavior that accumulates over a particular stream, or a combined Either stream, as described above.

edit: an example of one accumulation method over a merged stream (unchecked). Other implementations are possible. This does not cause both events to happen at the same time; rather, it allows you to combine the current state with past states so that you can always have the most recent left and Right values ​​available.

 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) 

It is still necessary to specify the initial values ​​for the Event streams. Think of it this way: if you only had events from Event a , what value should the second part of the tuple have?

+13
source

All Articles