Skip to main content

Atoms (active-state stores)

An atom holds a single immutable state value and lets you change it only through transitions — pure reducers (currentState, payload?) → newState. Dispatching a transition computes the next value and swaps the held one (the old value is dropped). This is the Redux store / Clojure atom model.

state Cart = { items: Integer, total: Number } // an immutable state type

atom cart {
initial Cart { items: 0, total: 0.0 }
transition addItem(s: Cart, price: Number) -> Cart {
return Cart { items: s.items + 1, total: s.total + price }
}
transition clear(s: Cart) -> Cart { return empty Cart }
}
cart.addItem(9.99) // dispatch: next = addItem(current, 9.99); held value swapped
cart.clear()
let n = cart.current.items // read the current immutable snapshot

Semantics

  • state T = { ... } declares an immutable state type (a compound type; you replace it, never mutate it in place).
  • atom name { initial <value> transition* } declares one holder seeded with initial.
  • A transition f(s: T, p: P) -> T is a reducer. Calling name.f(p) passes the current state as s automatically — you supply only the payload — then stores the returned value. A transition with no payload is just f(s: T) -> T.
  • name.current reads the current value.
  • Time-travel: every transition records the prior state, so name.undo() reverts to it (returning the restored value) and name.canUndo() reports whether there's anything to revert. History is bounded (the most recent 256 states), so undo can't grow memory without limit.

Notes & limits

  • One global instance per atom (no per-instance stores yet).
  • Transitions are synchronous and single-threaded.
  • A state whose fields use only String[]/user-type arrays is fine; primitive arrays (Integer[]) aren't supported yet (a general limitation).

A higher-level state machine layer (named states, a legal-transition graph, machine-wide data, and where guards) is also available — see Machines.

See examples/atom_demo.xi.