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 doeshold, 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.