ademenev

ademenev

Using states that are more than a single atom

AshStateMachine is all about transitions between states, and the state is represented by an atom. But transitions are only one part of FSMs, in general we want them to react on inputs, and the state is more than a single constant value.

Let’s consider a simple coffee vending machine that can make several types of drinks, each having its own price. In its initial state, the machine will only accept one input - “coin inserted”, and that input will transition to “drink selection” state. The input has an additional property – the coin’s monetary value, and the “drink selection” state should also store that monetary value. In “drink selection” state, two inputs can be accepted: “coin inserted”, which will keep the machine in “drink selection” state and increase the stored monetary value, and “drink selected” input which will transition to “drink preparation” state, but only if enough coins were inserted to cover the cost of the selected drink.

Reading the documentation, I do not see a declarative way to define that state machine. Am I missing something?

Marked As Solved

zachdaniel

zachdaniel

Creator of Ash

The main thing that makes ash_state_machine different in design from other state machine tools is that the actions are still the source of truth. The state transitions defined in the state machine block describe what transitions are allowed, and then in a given action you actually perform the state transition.

attributes do
  attribute :unspent_cents, :integer, allow_nil?: false, default: 0 
end

state_machine do
  transitions do
    initial_states [:waiting_for_coin]

    transition :coin_inserted, from: :waiting_for_coin, to: :drink_selection
    transition :drink_selected, from: :drink_selected, to: :drink_preparation
  end
end

actions do
  update :coin_inserted do
    argument :coin_amount, :integer, allow_nil?: false
    change atomic_update(:unspent_cents, expr(unsepent_cents + ^arg(:coin_amount))
    change transition_state(:drink_selection)
  end

  update :drink_selected do
    argument :selection, :atom, constraints: [one_of: [:coke, :diet_coke]]
    change set_attribute(:drink_selection, arg(:selection))
    change transition_state(:drink_preparation), where: [CanAffordDrinkSelection]
  end
end

This is just an example, certainly not 100% correct, but thrown together as an example of what it looks like in practice.

Where Next?

Popular in Questions Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
earth10
Hi, I’m just starting to build a side-project with Elixir and Phoenix and doing some basic test with Elixir alone. What strikes me is th...
New

Other popular topics Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43806 214
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54250 245
New

We're in Beta

About us Mission Statement