Statecharts support hierarchical states (or nested states) as a way to deal with the state explosion problem of traditional finite state machines.
An example of a nested state machine is a crosswalk light. You give the β when the stoplight is Yellow or Green. When the stoplight turns Red the crosswalk toggles to πΆββοΈ. The crosswalk light is a nested state machine of the parent stoplight.
In Robot nested state machines are represented as separate machines with invoke used to enter the child machine.
import { createMachine, invoke, state, transition, state as final } from 'robot3';
const stopwalk = createMachine({
walk: state(
transition('toggle', 'dontWalk')
),
dontWalk: final()
});
const stoplight = createMachine({
green: state(
transition('next', 'yellow')
),
yellow: state(
transition('next', 'red')
),
red: invoke(stopwalk,
transition('done', 'green')
)
});
You can transition through these states like so:
let service = interpret(stoplight, () => {});
service.send('next');
console.log(service.machine.current); // yellow
service.send('next');
console.log(service.machine.current); // red
let child = service.child;
console.log(child.machine.current); // walk
child.send('toggle');
console.log(child.machine.current); // dontWalk
console.log(service.machine.current); // green
service.send('next');
console.log(service.machine.current); // yellow
service.send('next');
console.log(service.machine.current); // red
child = service.child;
console.log(child.machine.current); // walk
child.send('toggle');
console.log(child.machine.current); // dontWalk
console.log(service.machine.current); // green
Since nested states is a useful feature of state machines you might want to simplify how to define substates. Thanks to Robot's composition properties it's easy to create a way declaratively define substates as part of a machine.
Here we create a nested
function that defines a submachine.
// A helper function for more easily building nested state machines.
const nested = (to, states) => invoke(
createMachine(states),
transition('done', to)
);
const stoplight = createMachine({
green: state(
transition('next', 'yellow')
),
yellow: state(
transition('next', 'red')
),
red: nested('green', {
walk: state(
transition('toggle', 'dontWalk')
),
dontWalk: final()
})
});