Skip to content

Glossary ​

All the documentation's terminology in one place, in plain words. Terms are grouped by theme; pages link to them by anchor.

The model of time ​

State ​

A value across time. At any moment you can ask a State "what are you right now?" — and there is always an answer: sample() responds whether or not anybody is listening. The text of an input, the current user, the mouse position: they exist at every moment, even when nobody is looking. Formally, a function from time to value (Time → A). Called Behavior in the FRP literature; previously named Wire in Continuum. A source state (state(init)) is written with .set(value) and .update((state) => next) — the updater folds over the value staged by the current moment, so several updates in one batch compose. More: States.

Behavior ​

Deprecated alias for State — the FRP-literature name for a value across time (Elliott & Hudak, 1997; the Sodium book). The alias still works today and will be removed in 1.0.

Stream ​

A stream of happenings. Unlike a State, you cannot ask an event "what are you now" — between firings it simply isn't. A click, a keypress, a server response: not values that exist, but things that happen. More: Streams.

Occurrence ​

One firing of an event. A pair of "moment + value": the third click, one specific server response. When we say "a Stream is discrete occurrences", we mean: an event is a set of individual firings, not a continuous quantity.

Discrete ​

Made of separate points rather than continuous. Discrete time is a sequence of individual moments (a tick, a click, a response) with nothing in between. The opposite is continuous time, as in physics. Continuum is discrete FRP: change happens in transaction-moments.

Moment / transaction ​

One atomic "tick" of logical time. Everything that follows from one event — all derived values — recomputes inside a single moment, as one whole: from outside you can never see "half" an update. "Logical" time because moments are counted by order, not milliseconds — only before/after/simultaneous matters. More: Transactions and time.

Simultaneity ​

Two occurrences in one moment. In callback world, "simultaneous" events actually run in some arbitrary order. In Continuum simultaneity is real: two events in one moment see the same world, and merging them (merge) forces you to say what to do with the pair.

Coalescing ​

Folding simultaneous occurrences into one. When two events happen in the same moment but one must come out, the coalescing function ((a, b) => … in Stream.merge) combines them. Without it you'd have to pick "who was first" — which is a race. A state's updates works the same way: however much happens inside a moment, it delivers exactly one coalesced occurrence for it.

Glitch ​

Observable half-updated state. The classic reactive-systems bug: sum = a + b where a has updated but b hasn't yet, and for an instant sum shows nonsense. In Continuum glitches are impossible by construction — a moment is atomic. The "diamond" example: Transactions and time.

Diamond ​

The dependency shape where glitches show up. One value feeds two branches which reconverge in a shared descendant: count → doubled, count → squared, doubled + squared → sum. Naive reactivity recomputes sum twice (the second time as a correction); a transaction does it once, correctly.

The hold delay ​

The rule: a State updates at the moment's boundary. Within the moment an occurrence arrives, hold/accum still show the old value. Sounds odd, but this is exactly what makes "the current value" well-defined when you look at it from the event that is changing it: the past is stable, the present is still forming. More: Transactions and time.

Fold ​

Accumulating an event's history into one value.clicks.accum(0, (_e, n) => n + 1) — "start at 0 and add 1 per click": a counter is a fold of clicks. The same move as Array.reduce, but over time instead of over an array.

push / pull ​

Two ways of delivering values. Streams push: something happened — it propagates through the graph. States pull: the value is computed when asked. Continuum is a hybrid: changes propagate by pushing, sample() reads by pulling.

Formulas vs state ​

Values are formulas; state and effects belong to a scope. A pure derived value (map, combine) is a recipe: it computes on demand, sleeps while nobody listens, and sample() still always answers. Anything that remembers or does — hold, accum, state, perform, .on — needs an owner: inside a component the scope is automatic; at module level you spell the lifetime out with root().

The network ​

Network / dependency graph ​

Everything you built out of States and Streams. map, combine, merge, at connect quantities into a directed graph: nodes are values and events, edges are "computed from". A component builds its piece of the graph once; updates flow through it afterwards.

Rank ​

A node's depth in the graph. The internal mechanism of glitch-freedom: nodes recompute in rank order (sources first, then deriveds, then deriveds of deriveds), so a node never fires before its inputs. You never touch ranks — they are just there.

at ​

An event photographs a value. draft.at(clicks, (text, click) => …) — "at the moment of the click, take the field's text"; draft.at(clicks) takes it as-is. The FRP replacement for the habit of "I'll read the variable inside the handler", but with exact semantics: at sees the value before the current moment (see the hold delay). The FRP literature calls this snapshot.

sample ​

Read a State's current value directly. s.sample() always answers — it is for code outside the network: initialization, tests, integrating foreign code. Inside the network prefer at — its simultaneity is defined.

Hatch ​

An explicit door between the pure network and the outside world. In: stream() / state() (inject a value). Out: listen (run a side effect), perform (do IO and return the result as an event). The word emphasizes that the network's boundaries are visible in the code, not smeared everywhere.

Result ​

An error as data. { ok: true, value } | { ok: false, error } — the outcome of IO where failure is an ordinary value branch, not a thrown exception. You can filter errors, accumulate them, render them — like any data.

Rendering ​

Fine-grained rendering ​

Exactly what depends on a value updates. Not "re-render the component and diff", but "this text node is bound to this State — patch it". This is why components run once and there is no virtual DOM.

Binding ​

A live link State → a piece of DOM. {count} in JSX doesn't mean "insert the current value"; it means "this text node now shows count, forever". Same for attributes: class={cls}.

Re-render ​

A foreign concept (React) we define ourselves against. Re-running a component function to compute a new tree. Continuum has none: a component runs once, updates travel through bindings.

Dynamic region ​

A stretch of DOM rebuilt from a value. The dyn primitive (and its sugar — Show, Dynamic): a subtree lives between comment markers; when the driving value changes, the old subtree is disposed and a new one is built. Values change bindings; structure changes through regions. More: Conditional rendering.

Keyed reconciliation / LIS ​

Matching list rows by key and reordering minimally. <Each> keeps one live subtree per key; on reorder it computes the longest increasing subsequence (LIS) and moves only what actually moved. More: List rendering.

last-request-wins ​

The response-race rule: the latest request wins. If the user asked for page 2 and then page 3, a late response for "2" is ignored. resource solves this internally by numbering requests.

Chunk / code splitting ​

Cutting the bundle into pieces loaded on demand. A literal import("./Page") in the code signals the bundler to emit a separate file (chunk), downloaded on first visit. Here — via the router's lazy.

Lifecycle ​

Ownership tree ​

Whoever builds it cleans it up. Everything a component creates (subscriptions, timers, nested regions) registers with its "owner"; disposing a subtree releases resources in a cascade — children first, then the parent. More: Ownership and lifecycle.

Scope ​

One node of the ownership tree — the owner of state and effects. Every component, dynamic region and <Each> row creates its own scope: it has its own onCleanup/onMount, the state (state, hold, accum) and processes (.on, perform) created inside register with it, and it dies as a whole. Pure formulas need no scope — they are just recipes.

root() ​

An explicit lifetime for module-level state. Inside a component, state gets its scope automatically. At module level there is no component to own it, so you say who does: const store = root(() => …) creates a top-level scope that owns everything built inside. Creating hold/accum/perform with no scope at all is a teaching error, not a silent leak.

Error boundary ​

A safety net for a piece of the page. If building or rebuilding a subtree throws, the nearest <Catch> above it disposes the broken subtree (with all its subscriptions) and shows a fallback instead of killing the whole app. More: Conditional rendering.

Cascading cleanup ​

Disposing a subtree frees everything inside automatically. A page goes away — its subscriptions unsubscribe, its timers stop, its portaled modals vanish. No "on unmount, remember to…" — the ownership tree remembers for you.

Context ​

Values available to descendants without prop drilling. provide puts a value into the current owner, use looks it up through ancestors. More: Context.

The wider world ​

Classic (discrete) FRP ​

The branch of FRP Continuum belongs to. Time is a sequence of transactions; combinators have exact semantics (Sodium, the Blackheath & Jones book). Contrasted both with Elliott's continuous FRP (time as in physics) and with the "reactivity" of signals/Rx. See History and context.

Denotational semantics ​

Defining constructs by mathematical meaning, not by implementation. "merge is the union of occurrence sets with coalescing of simultaneous ones" — an equation you can prove properties from (glitch-freedom, for one), not a description of a loop in code.

Signals ​

The neighboring reactivity tradition (Solid, Vue, Angular, TC39). Dependencies are tracked automatically when a value is read; the graph is implicit. Convenient to write; harder to reason about. The comparison lives in History and context.

The synchronous hypothesis ​

The 1980s synchronous-languages idea: a reaction is conceptually instantaneous. While the system reacts to an event, new events "wait outside" — which makes each reaction atomic. Continuum's transactions are a direct inheritance of this idea.