~ / track F / concurrency models
Functional reactive programming
AdvancedFunctional Reactive Programming (FRP) models a program as a graph of values that change over time — signals, streams, observables — connected by pure transformations. You declare the relationships: "the total displayed on screen is the sum of the items in the cart." When inputs change, the graph re-evaluates the dependents. UI frameworks like RxJS, ReactiveX, Re-frame, and the React rendering model are all FRP-flavored.
The two basic ideas
- Time-varying values. A
Signal[T]orStream[T]represents a value of typeTthat changes over time. Instead of repeatedly polling, your code subscribes to changes. - Pure transformations between them.
map,filter,combine,scan— the same vocabulary you use on collections, lifted to time. Connections in the graph are pure; effects happen at the leaves.
Streams in Clojure: a sketch
core.async channels are a small step away from FRP — you can build
stream-like pipelines on top. Here we'll simulate a stream of clicks
with a vector, just to feel the shape:
In an actual UI, clicks would be a live event stream and counts would be
a derived signal that updates whenever a click arrives. The structure of the
code is the same; the runtime swaps "reduce a vector" for "incrementally
update on each event."
Glitch-free dependency tracking
The hard part FRP libraries solve for you: when two signals depend on the same upstream signal, and that upstream changes, you must see a consistent snapshot downstream. Naive subscriptions can show intermediate states ("the sum was updated but the average hasn't recomputed yet").
A real FRP library batches recomputation in dependency order so observers never see inconsistent state. This is "glitch-free" reactivity.
Re-frame: FRP for the Clojure UI world
re-frame is the canonical Clojure FRP-flavored UI framework. The model:
- App-db: a single atom holding all UI state.
- Subscriptions: pure derivations from app-db. Components re-render when their subscriptions' values change.
- Events: messages that describe state transitions; handlers update app-db.
- Effects: side effects (HTTP, local storage) declared as data.
The flow is one-way: events → app-db → subscriptions → components → events. That's FRP packaged for production UIs.
When FRP fits
- UI code with many interdependent derived values. A naive "subscribe and update everything" approach explodes; FRP's dependency graph keeps it tractable.
- Stream processing pipelines. Real-time analytics, event-driven middleware, sensor data fusion.
- Anywhere "the consumer should react when the producer changes."
When the data is mostly static or single-shot, plain functions are simpler.
Check yourself
? quiz
What is the value of describing dependent computations as a graph instead of as imperative subscriptions and callbacks?
Exercise
Sketch (in code or prose) a tiny shopping-cart reactive graph with these signals:
items— vector of{:price ... :qty ...}subtotal— sum of(* price qty)across itemstax-rate— 0.10total—subtotal * (1 + tax-rate)
How does the runtime know to update total when items changes, but not
when an unrelated piece of state changes?