Search code examples
functional-programmingfrpelm

How do I get keepWhen behaviour in Elm 0.15?


The keepWhen function from earlier versions of Elm was removed. I have ported an Elm application from 0.14, but I'm stuck at trying to get one part of it to work, where it's using keepWhen.

So basically I'm looking for a function like

keepWhen : Signal Bool -> a -> Signal a -> Signal a

I have found

filter : (a -> Bool) -> a -> Signal a -> Signal a

but it's not quite the same thing, and I haven't figured out how to get it to work.


Solution

  • Answer: import it from a utility package

    The easiest way is to use Signal.Extra.keepWhen from the signal-extra package.
    (full disclosure: I'm the author)

    Important implementation detail

    Notice that the implementation isn't completely trivial. This is the implementation in the package (the Signal module is imported unqualified):

    keepWhen : Signal Bool -> a -> Signal a -> Signal a
    keepWhen boolSig a aSig =
      zip boolSig aSig
      |> sampleOn aSig
      |> keepIf fst (True, a)
      |> map snd
    

    The important difference with the version in kqr's answer is the sampleOn which keeps the output of keepWhen from updating when the boolean input changes. The difference between the two filters is that the keepWhen from 0.14 really only filters update events from the a input and doesn't sample it when the boolean input becomes True.

    The other implementation is also in signal-extra under the name sampleWhen.

    Diagrams

    If you know a little about marble diagrams, maybe these old diagrams may help. I'll just post a screenshot of the relevant ones below.

    The way you read these diagrams:

    1. Time flows from left to right.
    2. A line is a signal.
    3. The block is a function that takes the two signals above and produces the signal below.
    4. The shape at the left of each line is the initial value.
    5. A filled shape is an event on a signal.
    6. An outlined shape is for when the signal doesn't change.
    7. I've used shapes to represent types.
    8. I've used colours to represent different values.

    keepWhen and older keepWhen+sample marble diagrams

    Note that the second diagram, labeled as old behaviour, matches the behaviour of the code in kqr's answer.