1

In reactive-banana, given Event t (a, b), how would you lead it to (Event t a, Event t b)?

Traversable#sequence seems to solve it with some instance of Monad for (,) provided, but Event t is only Functor.

Ryoichiro Oka
  • 1,949
  • 2
  • 13
  • 20

1 Answers1

3

This should work:

import Control.Applicative

unzipEvent :: Event t (a, b) -> (Event t a, Event t b)
unzipEvent = liftA2 (,) (fmap fst) (fmap snd)

Notes:

  • The liftA2 (,) is general-purpose, as it is merely using the Applicative instance of functions. In this case, an equivalent alternative to it would be (&&&) from Control.Arrow. There is also a less fancy alternative, \e -> (fst <$> e, snd <$> e).
  • Even if Event t was Traversable, sequenceA wouldn't help. The Functor and Applicative instances for pairs are parametrised only on the second component of the pair. You'd end up with a (a, Event t b) result type, not to mention the Monoid constraint on a.
duplode
  • 33,731
  • 7
  • 79
  • 150
  • Thank you @duplode again for your answer, also I really appreciate your in-depth notes. I will look up `Arrow` as I've been interested in it. – Ryoichiro Oka Jul 28 '15 at 08:44
  • 4
    The `liftA2 (,)` is a red herring, this is just `unzipEvent e = (fst <$> e, snd <$> e)` written point-free. – Cactus Jul 28 '15 at 08:47
  • Thank you @Cactus for the easier looking solution! It was a good experience to follow types of the original combination tho. – Ryoichiro Oka Jul 28 '15 at 08:54
  • 1
    @Cactus Quite a bit, indeed. It's just that my first impulse was doing `fmap fst &&& fmap snd`, but as `Control.Arrow` is arguably even more of a red herring I switched to the other point-free spelling. – duplode Jul 28 '15 at 08:56
  • Just a relative quick question; how would you go backward, `(Event t a, Event t b) -> Event t (a, b)`? I tried with `liftA2` but `Event t` is not `Applicative` @duplode – Ryoichiro Oka Jul 28 '15 at 18:57
  • 1
    @RyoichiroOka Ugly, but should work: `fmap (\(Left x, Right y) -> (x, y)) . uncurry (unionWith (\(x,_) (y,_) -> (x, y))) . (fmap (dup . Left) *** fmap (dup . Right))`, with `dup x = (x, x)`. I wrote point-free for space; you'll likely prefer a less compact version. `(***)` is from Control.Arrow, and `unionWith` is the one from reactive-banana. For the final extraction from `Either` (unsafe in principle, but here we know it will work) you can use `fromLeft` and `fromRight` from `Data.Either.Combinators` in the `either` package. If the types are equal you don't need the `Either` tricks. – duplode Jul 28 '15 at 20:11
  • Thank you a lot again @duplode :) I will be posting some more questions and I hope you're still around – Ryoichiro Oka Jul 28 '15 at 20:17
  • Small correction: it should be `fromLeft'` and `fromRight'` instead of `fromLeft` and `fromRight` in the comment just above. – duplode Jul 28 '15 at 20:26