reflex-frp / reflex

Interactive programs without callbacks or side-effects. Functional Reactive Programming (FRP) uses composable events and time-varying values to describe interactive systems as pure functions. Just like other pure functional code, functional reactive code is easier to get right on the first try, maintain, and reuse.

Home Page:https://reflex-frp.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Looking for example for fan/fan-out of events

rubenmoor opened this issue · comments

I found documentation on fan here:

https://hackage.haskell.org/package/reflex-0.8.2.0/docs/Reflex-Class.html#v:fan

And the following code might merit the use of fan with DMap, only I don't know how to approach this. In the code, I split one event into several once, depending on the value inside.

let eChordAll       = catMaybes $ updated dynChord
    eChordToggle = filter (\c -> Raw.fromChord c == rawToggleKeyboard lang) eChordAll
    eChordArrowDown = filter (\c -> Raw.fromChord c == rawArrowDown lang) eChordAll
    eChordArrowUp = filter (\c -> Raw.fromChord c == rawArrowUp lang) eChordAll

    remainder chord =
      let raw = Raw.fromChord chord
      in     raw /= rawToggleKeyboard lang
          && raw /= rawArrowUp lang
          && raw /= rawArrowDown lang
    eChord = filter remainder eChordAll

Is there an example on how to use fan, or better: how to construct the dependent map inside the event somewhere?

For starters, here is a bit with fanEither:

let eChordAll                      = catMaybes $ updated dynChord
    (eChordToggle,    eChordRest0) = fanEither $ eChordAll <&> \c -> if Raw.fromChord c == rawToggleKeyboard lang then Left c else Right c
    (eChordArrowDown, eChordRest1) = fanEither $ eChordAll <&> \c -> if Raw.fromChord c == rawArrowDown lang then Left c else Right c
    (eChordArrowUp,   eChord)      = fanEither $ eChordAll <&> \c -> if Raw.fromChord c == rawArrowUp lang then Left c else Right c

This is sub-optimal given the chaining down to eChord.

Next step is fanMap:

data K = Toggle | Down | Up | Other
  deriving (Eq, Ord)

let eChordAll       = catMaybes $ updated dynChord
    selector = fanMap $ eChordAll <&>
      \c | Raw.fromChord c == rawToggleKeyboard lang -> Map.singleton Toggle c
         | Raw.fromChord c == rawArrowDown lang -> Map.singleton Down c
         | Raw.fromChord c == rawArrowUp lang -> Map.singleton Up c
         | otherwise -> Map.singleton Other c
    eChordToggle = select (Const2 Toggle) selector
    eChordDown = select (Const2 Down) selector
    eChordUp = select (Const2 Up) selector
    eChordOther = select (Const2 Other) selector

Note I transferred this issue isn't anything DOM-specific about it.

This is my final code:

{-# LANGUAGE MultiWayIf #-}

import Data.Functor.Misc (Const2 (Const2))

data FanChord
  = FanToggle
  | FanDown
  | FanUp
  | FanOther
  deriving (Eq, Ord)

                    let
                        eChordAll    = catMaybes $ updated dynChord

                        selector = fanMap $ eChordAll <&> \c -> if
                            | Raw.fromChord c == rawToggleKeyboard lang -> Map.singleton FanToggle c
                            | Raw.fromChord c == KI.toRaw @key kiDown   -> Map.singleton FanDown c
                            | Raw.fromChord c == KI.toRaw @key kiUp     -> Map.singleton FanUp c
                            | otherwise                                 -> Map.singleton FanOther c

                        eChordToggle = select selector (Const2 FanToggle)
                        eChordDown   = select selector (Const2 FanDown)
                        eChordUp     = select selector (Const2 FanUp)
                        eChordOther  = select selector (Const2 FanOther)

It compiles and works. Thanks a lot!

No problem! Glad to help out. Enjoy using reflex!