An introduction to Functional Reactive Programming
For Mathew Zaleski’s CSC302 (Software Engineering Large Systems) course at the University of Toronto, I created and delivered a set of lectures on Functional Reactive Programming.
The lecture slides are available here. This repo contains the complete code for the demos discussed in the slides.
The content below is intended to be a tutorial version of the lectures.
FRP-GOL-init | A very simple interactive FRP JS implementation of Conway's Game of Life. (Modeled directly on the Haskell FRP Game of Life from Tikhon Jelvis' talk, A Sensible Intro to FRP.) |
FRP-GOL-testable | A slightly more complex interactive FRP JS implementation of Conway's Game of Life, structured for improved testability over FRP-GOL-init. |
non-FRP-GOL | An interactive JS implementation of Conway's Game of Life, without using FRP principles. |
FRP-twitter | An FRP implementation of Twitter's "Who to follow" suggestions box. (Based on an example from Andre Staltz's The introduction to Reactive Programming you've been missing.) |
All demos use React.js, and all FRP demos use Bacon.js.
To run any of the demos locally, simply download its main directory and open index.html.
To modify any of the demos, start by running npm install
inside its main directory to install the required Node.js modules.
Build a demo after modifying it by running npm run build
inside its main directory, or run npm run watch
to automatically re-build the demo each time it is modified.
Some modifications may require additional Babel plugins to be installed (see http://babeljs.io/docs/plugins).
We need:
We also want:
We would like to implement the game logic as a function, which takes a previous game state and produces the next game state.
Moreover, we would like to treat the function as a black box: it doesn’t matter how it is implemented; we can trust that it will correctly produce the next state if we give it the previous state.
This means that we can produce new states forever if we
What’s functional about this model?
It has no side effects (interaction with anything outside the model):
What is the advantage of having a functional model? –> Testability
What’s the problem with this code?
function crazyDouble(x) {
if (new Date.getDay() == 4) // if today is Wednesday
return x*3;
else
return x*2;
}
// We'd like to apply crazyDouble to all the elements of a list...
var doubled = []
for (var elem of [1, 2, 3])
doubled.append(crazyDouble(elem))
How do we test crazyDouble
?
crazyDouble
to the elements in parallel, or in a different order, for optimization…We want to trigger an update (i.e. call our update function)…
Can we treat clicks and ticks as events, and implement event handlers? –> What are the challenges of this implementation? –> How would we test this implementation?
Can we create an observable object that holds clicks and ticks, subscribe to it, and trigger an update when a click or tick occurs?
(What is the difference between event handling and observer/observable?)
(Adapted from https://csc301-fall-2016.github.io/resources/lec6-2–2016-10-25.pdf)
…a declarative programming paradigm concerned with data streams and the propagation of change
Reactive Systems are:
- Responsive: The system responds in a timely manner if at all possible.
- Resilient: The system stays responsive in the face of failure.
- Elastic: The system stays responsive under varying workload.
- Message Driven: Reactive Systems rely on asynchronous message-passing to establish a boundary between components that ensures loose coupling, isolation and location transparency.
Introduction to Reactive Programming:
Reactive programming is programming with asynchronous data streams.
At the core of any system are values, which exist for some continuous period (eg. variables, pixels, mouse position). We’ll refer to these as “behaviours”.
But computers don’t operate continuously (in real time).
And we’re not necessarily interested in behaviours at every point in time (eg. do we always care when the user moves the mouse?).
So we want to examine certain behaviours, in a way that doesn’t depend on time.
We can describe specific conditions on a behaviour, which we’ll call “events”.
Events are discrete (they only occur at specific points in time).
We need a way to model events and have our system handle them…
If we can connect our system to an input stream, then we can add events to the stream as they occur, and our system can react to them as it receives them.
(Notice that our system still has no side effects!)
We don’t model time, because the timing of an event doesn’t matter to our system!
We are only interested in:
What if we have multiple kinds of events (eg. clicks and ticks)?
We can create streams of each of these events - and then we can combine them (or create new kinds of events) using functional patterns.
Licensed under the MIT License. See LICENSE for more information.