On my journey learning Elixir I encounterd a new problem (or challenge).
This the context of the problem. I have a program/function generating simple values like: :one, :one, :one, :two, :one, :two, …
After each generated value a function f(x) is directly called and the function value is an input for a state transition function. (Actually I’m calculating a fitness function in a machine learning program.)
For some reasons I needed a lightweight Finite State Machine. So I decided to use SasaJuric’s fsm. It’s using only macros and data structures instead of state servers.
The solution I thought of is; HbsFsm is the state engine:
case f(x) do
:one -> HbsFsm.one
:two -> HbsFsm.two
end
Following is the code I tried of a simple example using the fsm:
defmodule HbsFsm do
use Fsm, initial_state: :my_state, initial_data: 0
defstate my_state do
defevent one , data: sum do
next_state(:my_state, sum)
end
defevent two , data: sum do
next_state(:my_state, sum + 1 )
end
end
end
#----------------------------------------------------------
defmodule FsmTest do
use ExUnit.Case
test "Process event" do
assert (
x = :one
HbsFsm.new
case x do
:one -> HbsFsm.one
:two -> HbsFsm.two
end )
end
end
Running this code gives the next error message:
test Process event (FsmTest)
test/testfsm_test.exs:5
** (UndefinedFunctionError) function HbsFsm.one/0 is undefined or private. Did you mean one of:
Basically, think of Hbs.Fsm as spawning an instance of an fsm that you need to pass around the pid of, vs spawning a global FSM.
As an aside, I’m not sure I’d recommend using this macro based API, and honestly I’m not sure if @sasajuric still recommends using them. I think that they can be a handy short hand when you want to get something going but for learning purposes I’m afraid it hides too much away.
There’s also the issue that it doesn’t teach you want the ordinary fsm syntax / usage looks like which means you aren’t well equipped to tackle even identical functionality in other code bases when you’re first starting out.
When it comes to my FSM library, the machine is not powered by a separate process, and I still believe this is usually a more suitable approach to build FSMs compared to gen_statem (or gen_fsm). That said, I indeed don’t advise using my library anymore (see my comments in this issue). Plain pattern matching backed by maps or structs IMO works just fine.
The fsm lib is used in sigaws AWS V4 signature library for testing. Specifically for reading the AWS signature testsuite data file. Take a look at this file:
The fsm lib was used here before becoming aware of Sasa Juric not recommending it any longer! Didn’t put in any effort to change its usage as it is used only for testing and it just works!