@klauss.net/statemachine v1.0.0
State Machine
A Finite State Machine is an abstract machine used to represent the flow of an algorithm in sequential, easy to follow steps that will allow readers to understand the algorithm's implementation, function and purpose. Using Finite State Machines, you develop flexible algorithms without having to understand the ins and outs of said algorithm. Simply construct a State Machine, specify the states and logic around them, give some input and you've got your algorithm implemented. Of course a solid understanding of these abstract machines is necessary before diving into this (arguably, simple) library.
We've written a little article about these State Machines and their function for you as well as documentation on the library itself.
What is a State Machine
As mentioned, a State Machine is an abstraction of a physical machine who's job is to express and sometimes even perform logical or state-based calculations based on particular inputs. In other words, they behave like switches that move depending on some factor.
They are generally represented graphically using simple rules: 1. All states are represented as circles. 2. All states are connected to each other using arrows. 3. Each state transition is conditional. 4. An accepting state is double-outlined. 5. State names are placed inside the circle of the state. 6. All labels on arrows are treated as conditions
Take this State Machine as an example:
As you can see, the circles represent states. The state A
is an accepting one, more on that later.
How do they work
Taking another look at the example above, you'll notice that providing an input of 0
anywhere won't change the current state. Meaning if a 0 is encountered, the state will move to itself.
However, should a 1
be encountered, the state will change.
To put it simply, this state machine will toggle between states A
and B
on a 1
input but won't change on a 0
input.
Fun Fact: State Machines are the basis of Regular Expressions. Without State Machines, a lot of pattern matching would be a lot more difficult.
An advanced enough state machine could theoretically do anything - Computers are just mighty state machines!
This State Machine library simply works by requiring the user to predetermine the states along with conditions that can be used to map inputs to outputs. The library can take the machine's shape in several formats. The recommended format is through an Object containing states as functions and declaring them as accepting seperately. To do this, you are required to provide an Object containing the state's name or identifier which is used by other states to navigate to it, and the value being essentially, a resolver function.
The code
An example of the above's machine's states would be
{
'A': input => {
if (input === 0)
return 'A';
else
return 'B';
},
'B': input => {
if (input === 0)
return 'A';
else
return 'B';
},
}
As you can see, the resolver functions simply return the name of the state they jump to.
To initialise a state machine, you pass this object into the StateMachine
constructor function line so
const StateMachine = require('finitestatemachine');
const SM = new StateMachine( { ... } );
This however is not the only way to declare states. You can declare them through an array like so:
new StateMachine( [ input => ... ] );
The advantage of this method is that states are automatically named by index and any states followed by a boolean
variable type will have their acceptance values set to its value.
Declaring a state as accepting involves another step: passing the state's name to the constructor by name in an array.
new StateMachine( { ... }, ['A'] );
This will render state A
as accepting.
Like everything, there are alternatives. You can pass an object containing the acceptance values of each state too:
new StateMachine( { ... }, { 'A': true } );
or better yet, you can pass a resolver function:
new StateMachine( { ... }, stateName => true );
Running
A statemachine
instance also provides simplified functions for calculating states by inputs.
there are four three ways to calculate values:
run
,headless
step
all
the run
and headless
function takes an array of arguments which are called on the state resolvers who will decide the state to proceed to next.The difference being run
returns
the state's name upon completion, -1 if the state is not accepting whereas headless
will only return whether it's accepting at all.
step
is a broken down version of run
.
Rather than taking an array of arguments, it takes a single one. It too returns the new state's name or -1 if it does not exist.
all
takes an array of arrays. Provide it a list of input sets to try and get back an array of the results.
5 years ago