On this page:
1.1 Types and Predicates
state-machine
state
transition
machine-execution
machine-history-event
1.2 Construction
make-state-machine
make-state
make-transition
no-behavior
no-guard
1.3 Execution
make-machine-execution
machine-execution-start
machine-execution-complete?
handle-event
complete-current-state

1 Module behavior/fsm

 (require behavior/fsm) package: behavior

This module provides the ability to define, and then execute, state machines using a flexible yet capable model. The definition model provides a state machine that contains a set of discrete states, each state has a set of outbound transitions each of which may be associated with a trigger event. Note, wherever possible the terminology and relationships in the state machine model follow those of the Unified Modeling Language (UML).

State machine definition details:

Examples:
> (define simple-fsm (make-state-machine
                      'first-fsm
                      (list (make-state 'hello 'start)
                            (make-state 'goodbye 'final))
                      (list (make-transition 'hello 'goodbye #:on-event 'wake))
                      '(sleep)))
> (define log-string (open-output-string))
> (with-logging-to-port
      log-string
    (lambda ()
      (let* ([exec (make-machine-execution simple-fsm (make-logging-reporter))]
             [started (machine-execution-start exec)]
             [next1 (handle-event started 'sleep)]
             [next2 (handle-event next1 'wake)])
        (void)))
    'info)
> (for-each displayln
            (map (curryr list-tail 3)
                 (map (λ (line) (string-split line " " #:repeat? #t))
                      (string-split (get-output-string log-string) "\n" #:repeat? #t))))

(starting #<state> #f ()))

(enter-state #f #f ("#<procedure:no-behavior>")))

(execute-state #f #f ("#<procedure:no-behavior>")))

(handle-event #<state> #f ("sleep")))

(handle-event #<state> #<transition> ("wake")))

(exit-state #<state> #f ("#<procedure:no-behavior>")))

(transition #<state> #<transition> ("#<procedure:no-guard> => #t")))

(transition-effect #<state> #f ("#<procedure:no-behavior>")))

(enter-state #<state> #f ("#<procedure:no-behavior>")))

(execute-state #<state> #f ("#<procedure:no-behavior>")))

(completed #<state> #f ()))

A state machine is executed by constructing a machine-execution and then calling execution-start. This will transition to the start state and perform any behaviors associated with it. The state machine only transitiona from one state to another in response to an event (via handle-event) or by state completion (via complete-current-state). The state machine is completed when it transitions into either a 'final state, or a state with no outgoing transitions.

Additional execution details:

1.1 Types and Predicates

struct

(struct state-machine (name states events transitions))

  name : symbol?
  states : (hash/c 'symbol state?)
  events : (hash/c 'symbol (listof transition?))
  transitions : (hash/c 'symbol (listof transition?))
The state machine definition, returned by make-state-machine, and which defines the states and transitions and has been validated to be correct. The three hash values are constructed as optimization for the execution and comprise name to state, event to transition, and source state to transition respectively.

struct

(struct state (name kind entry execution exit))

  name : symbol?
  kind : (or/c 'start 'normal 'final)
  entry : (-> machine-execution? void?)
  execution : (-> machine-execution? void?)
  exit : (-> machine-execution? void?)
Represents a state within the state-machine, also included in certain machine-history-event instances.

struct

(struct transition (source-name
    target-name
    internal
    trigger-event
    guard
    effect))
  source-name : symbol?
  target-name : symbol?
  internal : boolean?
  trigger-event : symbol?
  guard : (-> machine-execution? symbol? boolean?)
  effect : (-> machine-execution? void?)
Represents a transition within the state-machine, also included in certain machine-history-event instances.

struct

(struct machine-execution (model condition current-state))

  model : state-machine?
  condition : (or/c 'created 'active 'in-error 'complete)
  current-state : state?
This represents the current state of a state machine execution, note that calls to handle-event and complete-current-state return new copies of this structure.

struct

(struct machine-history-event history-event (current-execution
    kind
    source
    transition
    evaluations)
    #:transparent)
  current-execution : machine-execution?
  kind : symbol?
  source : (or/c #f state?)
  transition : (or/c #f transition?)
  evaluations : (listof string?)
These events are sent to the reporter associated with discrete actions taken as part of the state machine execution. For example, kind may be one of 'starting, 'enter-state, 'execute-state, 'exit-state, 'handle-event, 'transition, 'transition-effect, or 'completed.

1.2 Construction

procedure

(make-state-machine name    
  states    
  transitions    
  [additional-events])  state-machine?
  name : symbol?
  states : (non-empty-listof state?)
  transitions : (non-empty-listof transition?)
  additional-events : (listof symbol?) = '()
Construct a new state-machine, all validation of the model is performed during construction and reported as exn:fail:contract exceptions.

procedure

(make-state name    
  kind    
  [#:on-entry entry    
  #:execute execution    
  #:on-exit exit])  state?
  name : symbol?
  kind : (or/c 'start 'normal 'final)
  entry : (-> machine-execution? void?) = no-behavior
  execution : (-> machine-execution? void?) = no-behavior
  exit : (-> machine-execution? void?) = no-behavior
Construct a new state.

procedure

(make-transition source-name    
  target-name    
  [internal    
  #:on-event trigger-event    
  #:guard guard    
  #:execute effect])  transition?
  source-name : symbol?
  target-name : symbol?
  internal : boolean? = #f
  trigger-event : (or/c #f symbol?) = #f
  guard : (-> machine-execution? symbol? boolean?) = no-guard
  effect : (-> machine-execution? void?) = no-behavior
Construct a new transition, note that by using symbols for the sourvce-name and target-name we do not need to reference state instances directly and the construction is considerably easier to read/understand.

Example:
> (make-state-machine
   'first-fsm
   (list (make-state 'hello 'start)
         (make-state 'goodbye 'final))
   (list (make-transition 'hello 'goodbye #:on-event 'wake)))

#<state-machine>

value

no-behavior : (-> machine-execution? void?)

A default behavior implementation that does nothing.

value

no-guard : (-> machine-execution? transition? boolean?)

A default guard implementation that simply returns #t.

1.3 Execution

procedure

(make-machine-execution from-machine    
  [reporter])  machine-execution?
  from-machine : state-machine?
  reporter : (or/c #f (-> machine-history-event? void?)) = #f
Construct a new machine-execution using from-machine as the definition. The returned execution will be in the 'created condition.

Transition to the start state of the machine. The returned execution will be in the 'active condition.

procedure

(machine-execution-complete? exec)  boolean?

  exec : machine-execution?
Returns #t if the execution is in the 'completed condition.

procedure

(handle-event exec event)  machine-execution?

  exec : machine-execution?
  event : symbol?
Consume the event and determine the next action. The returned execution will be in either the 'active, 'in-error, or 'completed condition.

Complete the current state and determine the next action. The returned execution will be in either the 'active, 'in-error, or 'completed condition.