What is a Dynamic?

The Behavior carries some state around, and the Event fires with the value of the new state whenever the state is changed. This is useful for reasons of efficiency. Behaviors are pull-based, which means we need to poll them for changes, so combining a Behavior with an Event that fires when it updates means that we can write code that reacts to changes in state at the time when the changes occur.

This is very useful when we want to update a piece of the DOM. A Dynamic t Text can be passed from where it was created, through the application, down to a DOM node that needs to display some changing text. The Behavior t Text takes care of tracking the current state of the text to display, and reflex-dom can set up some code to replace the text in the DOM node whenever the Event signals that there is a change.

The reflex and reflex-dom libraries aren’t prescriptive about how you structure your application, but the common advice is to pass Dynamics as far down as possible into the code that generates DOM. If you follow that advice then you can arrange things so that your code is doing the same changes to the DOM as the various virtual DOM libraries would, but skipping the need to diff and patch the various DOM trees.

There is some reference to building an Event and Behavior simultaneously in the reactive-banana documentation, and it appears in one of the examples, and so I suspect that the idea behind the Dynamic is probably lurking in the background or in the folklore of other Event-and-Behavior FRP systems.

It is really common in FRP systems like these to deal with Events which have functions for values, which is worth remembering when you’re starting out and trying to solve problems like these for the first time. It can seem really strange at first but you will get comfortable with it if you practice for a while and try to remember that functions are values too.

We are planning on creating some buttons to produce these Events, and so the Events won’t happen simultaneously. However, since we have separated out the logic from the controls, and are taking Events as inputs, we can’t guarantee that the Events will be happening in different frames.

We are working with Event t (Int -> Int), so we’ll combine the Events using mergeWith and function composition:

Bringing RecursiveDo into the picture

Behaviors have values at all points in time, and Events only have values at certain instants in time. This means that all Behaviors have a value before any Events in the application fire, and so any Event can be used to sample from a Behavior.

We can use one firing of a particular Event to build up a Behavior and a later firing of the same Event to sample a Behavior. Going further than this, we can use one firing of a particular Event to both build up and sample from a Behavior. The reason this is fine is that hold updates the Behavior in the next frame rather than the current frame.

The result of this is that we are able to have loops in the graph of our FRP network. This is fine, and is often very useful, but we need a language extension to be able to input them into Haskell in a convenient manner.

Imagine that we had an application that contained a counter that we wrote earlier, and that we wanted to specify an upper limit for the value of the counter.

We could add something like this to the settings page for the application:

We’re still playing with basic examples, but hopefully these examples plus a bit of imagination are enough to help see the usefulness of building up, passing around and pulling apart first-class values for state management.

Removing extraneous updates

There is a small trap here when we start decomposing our Dynamics.

Imagine that we constructed a Dynamic that keeps track of a pair of Colours:

Imagine that the first Event passed to dynPair never fires. Whenever the second Event passed to dynPair fires, the output Dynamic will update. If that output is passed through splitPair we’ll have a pair of Dynamics that are updating, although the first of these will have an Event firing that doesn’t correspond to a change in state.

This is particularly problematic if we’re trying to minimize the number of times we have to update a DOM tree.

We can see that in action here if we click back and forth between “Red” and “Blue” for one set of inputs:

Which does what we want with respect to minimizing unnecessary updates:

This highlights an additional issue with our implementation of dynPair - if we clicked the same button over and over, we’d trigger updates even when the state wasn’t changing. If this was important to us we could address this by using holdUniqDyn within dynPair itself.

Playing along at home

If you want to test out your understanding of Dynamics, there are Dynamic-themed exercises here. These exercises build up incrementally as the series progresses, so it would probably best to start the exercises beginning at the start of the series.

Next up

We now have all the pieces that we need to build an FRP network.

In the next post we’ll start looking at how to create DOM elements using reflex-dom.