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.
https://reflex-frp.org
BSD 3-Clause "New" or "Revised" License
1.07k stars 149 forks source link

runWithReplace makes "now" events disappear #462

Closed parenthetical closed 2 years ago

parenthetical commented 2 years ago

I ran into some surprising behavior in a Reflex DOM app. I assumed the following events a and b would have occurrences at the same time as e:

let e :: Event t () = ...
a <- switchHoldPromptOnly never (pushAlways (const now) e)
b <- switchHoldPromptOnly never . snd =<< runWithReplace (pure ()) (now <$ e)

However, only event a does, while b has no occurrences. What could be causing this?

parenthetical commented 2 years ago

Another surprising behavior: when replacing now with pure e, the a event gets an occurrence for every e occurrence, while the b event does not have the first e occurrence. I.e. counting both a and b will have b lagging behind by one, staying zero for the first occurrence.

let e :: Event t () = ...
a <- switchHoldPromptOnly never (pushAlways (const (pure e)) e)
b <- switchHoldPromptOnly never . snd =<< runWithReplace (pure ()) (pure e <$ e)
ryantrinkle commented 2 years ago

This is because the widget builder monad can't be run inside MonadPush, so runWithReplace actually builds the new widget after the current frame ends. After that, usually on the next frame, its result event fires.