StateMachines package is functional implementation of a deterministic finite-state machine (DFSM) - also known as a deterministic finite automaton (DFA). It can be used as a simple transition state system, as a business workflow or as a autonomous state machine.
Implementation follows the definition of a deterministic finite automaton M that is a 5-tuple, (Q, Σ, δ, q0, F), consisting of:
- a finite set of states (Q)
- a finite set of inputs - actions and context (Σ)
- a finite set of transitions or transition function (d: Q x Σ -> δ)
- an initial or start state (q[0])
- a set of accept or final states (F)
using Pkg
Pkg.add("https://github.com/filipemlourenco/StateMachines.jl")
using StateMachines
- Create an automaton (
Automaton
) - Execute the automaton (
exec
orexec!
)
Automaton instatiation:
t = Transition(from::State, to::State)
t = Transition(from::State, to::State, input::Symbol)
t = Transition(from::State, to::State, input::Function)
a = Automaton(ts::Vector{Transition})
a = Automaton(states::Vector{State}, ts::Vector{Transition})
a = Automaton(states::Vector{State}, ts::Vector{Transition}, start::State)
Automaton execution:
exec!(a::Automaton; context::Any = nothing)
exec!(a::Automaton, action::Symbol; context::Any = nothing)
a1 = exec(a::Automaton; context::Any = nothing)
a1 = exec(a::Automaton, action::Symbol; context::Any = nothing)
a1 = exec(a::Automaton, s::State, action::Union{Symbol, Nothing}; context::Any = nothing)
Create an automaton with only the transitions states. Initial state will be the state from the first transition and no final stage will be set. Accepted states and inputs (actions) will be infeered from the transitions.
a1 = Automaton([
Transition(State("s1"), State("s2"), :create),
Transition(State("s2"), State("s3")),
Transition(State("s1"), State("s4"), :update),
])
or (states can be replaced by a string)
a1 = Automaton([
Transition("s1", "s2", :create),
Transition("s2", "s3"),
Transition("s1", "s4", :update),
])
or (instantiation with acceptable state list and initial state)
a1 = Automaton([Transition("s1", "s2", :create), Transition("s1", "s4", :update)],
states = ["s1", "s2", "s3", "s4"],
start = "s1"
)
Simple automaton execution:
next_state = StateMachines.exec(a1, :create)
Automaton execution as a transition system (e.g. workflow):
current_state = State("s1")
next_state = StateMachines.exec(a1, current_state, :create)
Automaton execution as a self (or autonomous) state machine:
StateMachines.exec!(a1, :update)
workflow = Automaton([
Transition("Draft", "Prepared", :prepare),
Transition("Prepared", "Reviewed", (action, context) -> action == :review && context.var1 == 0),
Transition("Prepared", "Draft", :update),
Transition("Reviewed", "Archived", :archive),
Transition("Reviewed", "Draft", :update),
])
record = (name = "my business record", state = "Draft", var1 = 1, var2 = 2)
new_state = StateMachines.exec(workflow, record.state, :prepare, context = record)