Question

Let's say I have

x :: Event t (A,B)

I can get the first component of it:

fst <$> x :: Event t A

However, this event will fire even when the first component doesn't change. I want to avoid that, because it would trigger an expensive recomputation.

A is an instance of Eq, so I want to be able to remove the successive events where the first component is not changed compared to its last value.

Ideally, I'd like a function

filterDups :: Eq a => Event t a -> Event t a

which would do that without resorting to the Moment monad. Is it possible? Or what's the best way to do this?

Was it helpful?

Solution

You have to remember information about the history of the event to do what you want. As other answers have already mentioned, you can use accumE for that purpose. Here a succinct definition:

unique :: Eq a => Event t a -> Event t a
unique = filterJust . accumE Nothing
       . fmap (\a acc -> if Just a == acc then Nothing else Just a)

OTHER TIPS

I've never used reactive-banana, and haven't tested this, so beware. Nevertheless, here's one idea that at the very least typechecks. We'll use accumE to remember something about past events.

notice x (old, new) = (new, Just x)

changed (Just old, Just new) = guard (old /= new) >> return new
changed (_, new) = new

justChanges :: Eq a => Event t a -> Event t a
justChanges e = filterJust $ changed <$> accumE (Nothing, Nothing) (notice <$> e)

This solution uses (or abuses) the fact that the stepper function updates the Behavior "slightly after" the Event, see the comment in the docs.

First create a Behavior based on the Event, you have to find a suitable first value for the Behavior in your solution, for simplicity I am assuming that the first element of your pair is an Int:

x :: Event t (Int, b)

firstB :: Behavior t Int
firstB = stepper 0 $ fst <$> x

Then you can use the filterApply function:

filterDups e = filterApply (firstNotEq <$> firstB) e
    where firstNotEq old (new, _) = new /= old
          firstB                  = stepper 0 $ fst <$> e

Take a look at this gist for a simple example using the Threepenny GUI.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top