6

In reactive-banana I've got an event stream that produces a series of numbers, some of which repeat several times in a row (I'm not concerned with all duplicates, just sequential duplicates). How can I modify that event stream to contain only non-sequential duplicates?

I tried using changes to convert it to a behavior thinking the behavior would only "change" when the event was a new number but instead the behavior triggers a change event every time a new input event is received.

Orclev
  • 695
  • 1
  • 6
  • 16

2 Answers2

5

Note that the changes function should only be used for binding to GUI toolkits and thelike, it should not be used for regular programming with events and behaviors.

A function that supresses duplicate event occurrences can be expressed in terms of the mapAccum and filterJust combinators as follows

skipEqual :: Eq a => Event t a -> Event t a
skipEqual = filterJust . fst . mapAccum Nothing . fmap f
    where
    f y (Just x) = if x == y then (Nothing,Just x) else (Just y,Just y)
    f y Nothing  = (Just y, Just y)

test = interpretModel skipEqual $ map (:[]) [1 :: Int,1,2,3,3,2]

Running test gives

*Main> test
[[1],[],[2],[3],[],[2]]

as desired.

In other words, you can simply imagine Event as a list of occurrences and then apply your beloved "list" combinators to that.

Heinrich Apfelmus
  • 11,034
  • 1
  • 39
  • 67
  • Oh, why didn't I think of that?! I've removed the ugly implementation from my answer in favour of this one. – ehird Apr 03 '12 at 17:41
  • 1
    if you shouldn't use changes, how do you do anything meaningful with a behavior? – Orclev Apr 04 '12 at 00:26
  • @Orclev: You can `apply` behaviors to events. The `<@>` and `<@` operators are used for that. Also, you can use mutual recursion between behaviors and events. – Heinrich Apfelmus Apr 04 '12 at 07:36
0

Well, changes doesn't turn anything into a Behavior; it just lets you observe the changes of a Behavior in NetworkDescription, so that you can glue it to external frameworks. The behaviour of changes is described as changes (stepper x e)return (calm e), so round-tripping an event through stepper and changes will have no effect other than calm (which simply discards all simultaneous occurrences but the first).

It's useful to have a combinator to discard occurrences that don't change the value, and I think some other FRP frameworks have one built in. But you can write your own pretty easily, as Heinrich's answer shows.

ehird
  • 40,602
  • 3
  • 180
  • 182