State machines (statecharts)
wireform-state-machine is a typed statechart library with a chart
specification that lives at the type level. The compiler rejects errors that a
string-keyed machine would otherwise find only at runtime:
- a transition targeting a missing state, a duplicate state key, an undeclared
event, or
OnDoneoutside anInvokeis aTypeErrorthat names the chart, the offending key, and the valid alternatives; - each name role — states, events, guards, actions, services, invoke ids, and done-data outputs — is a separate sum type used as a kind, so an event in a state position is a kind error;
- guards, actions, services, and output producers live in completeness-checked registries, so missing, duplicate, or foreign implementation keys are compile errors;
- events carry typed payloads, context is a typed machine-wide value, and final output has its declared Haskell type.
The runtime implements SCXML statecharts: compound and parallel states,
shallow/deep history, guarded transitions, entry/exit/transition actions,
eventless (Always) and delayed (After) transitions, promise/callback/child
invocations with OnDone/OnError, done events with data, wildcard and
root-level handlers, internal transitions, and typed machine output.
data ToggleState = Off | Ondata ToggleEvent = FLIP
deriveKeyKind ''ToggleStatederiveKeyKind ''ToggleEvent
type Toggle :: ChartSpec ToggleState ToggleEvent NoKey NoKey NoKey NoKey NoKeytype Toggle = Chart "toggle" () () '[ 'FLIP ::: () ] '[ State 'Off '[ On 'FLIP ==> To 'On ] , State 'On '[ On 'FLIP ==> To 'Off ] ] 'Off
impl :: ChartImpl IO Toggleimpl = chartImpl RNil RNil RNil RNil (const ())Documentation
Section titled “Documentation”This catalogue page maps the package. The State machines guide contains the tutorial and API guide:
- Overview & hello world — the shape of a program.
- State machine concepts — states, configurations, events, transitions, guards, actions, hierarchy, parallel regions, history, macrosteps, and effect requests.
- The chart type — the type-level DSL and the
TypeErrors that reject bad charts. - Implementing a chart —
chartImpl, the four registries, guards/actions/services. - Running a machine — the pure
step, effect requests, and the IO interpreter (timers, subscriptions, actors). - Testing with the simulator — the virtual clock, scripting timer/service races, chart lints.
- Persistence & recovery — snapshots, fingerprints, and recovery for evolving charts.
- Visualization — Stately config, Mermaid, DOT, self-contained HTML.
Module map
Section titled “Module map”| Module | What lives there |
|---|---|
StateMachine | umbrella re-export of the whole surface |
StateMachine.Key | singleton keys: SKey, KeyKind/KnownKey, reify/demote, deriveKeyKind |
StateMachine.Spec | the type-level chart DSL |
StateMachine.Validate | well-formedness TypeErrors (ValidChart) |
StateMachine.Reify | demotion of the spec to the runtime chart (KnownChart) |
StateMachine.Event | typed events + typed lifecycle channels; decoding for named external events (decodeEvent) |
StateMachine.Registry | completeness-checked guard/action/service/output registration |
StateMachine.Machine | the abstract machine value, chartImpl |
StateMachine.Step | pure SCXML macrostep semantics |
StateMachine.Persist | snapshots, restore, recovery strategies |
StateMachine.Interpret | the IO interpreter (timers, services, actors) |
StateMachine.Debug | deterministic simulation, trace rendering, chart lints |
StateMachine.Render.* | Stately config, Mermaid, DOT, self-contained HTML |
Try it
Section titled “Try it”cabal run example-trafficruns the traffic-light demo through a pedestrian cycle, a power outage with
history restoration, snapshot/restore, stale-snapshot rejection, Recovery
restart, typed final output, and all four renderers.