Home > F# > Making a simple State Machine with F# Actors

Making a simple State Machine with F# Actors

F# comes with a built-in Actor framework, using the MailboxProcessor class.  The main reason for using actors is to simplify concurrent processing, but they also hit another sweet spot – they’re pretty good for implementing Finite State Machines (FSM).

I won’t go into the detail of how to implement a standard actor, but here’s a simple example which maintains a sum of the numbers posted to it.  It uses an asynchronous workflow which runs it asynchronously in a different thread, and a recursive function to maintain the state (although as an actor’s state is not shared, mutable state would be acceptable):

let countingActor =
  MailboxProcessor.Start(fun inbox ->
    let rec loop num = async {
      do printfn "num = %i" num
      let! msg = inbox.Receive()
      return! loop(num+msg) }
    loop 0)

And here it is being called in FSI:

countingActor.Post 10;;
num = 10
val it : unit = ()

countingActor.Post 5;;
num = 15
val it : unit = ()

Perhaps this is not the most elegant-looking or understandable code – I hear actors in Erlang and Scala are much more succinct – but once you give it a try it starts to make sense. For what we’re about to consider, the important point to note is that the recursive ‘loop’ function is being called infinitely, each time waiting until a message has been received.

So, how to make a state machine with it?  To keep this as simple as possible, let’s consider a hugely inefficient climate control system which has only two states – heating and cooling.  We can define this as a MailboxProcessor:

// define the messages which can be used to change the state,
// using a Discriminated Union
type message =
    | HeatUp
    | CoolDown

// define the actor
let climateControl = MailboxProcessor.Start( fun inbox ->

    // the 'heating' state
    let rec heating() = async {
        printfn "Heating"
        let! msg = inbox.Receive()
        match msg with
        | CoolDown -> return! cooling()
        | _ -> return! heating()}

    // the 'cooling' state
    and cooling() = async {
        printfn "Cooling"
        let! msg = inbox.Receive()
        match msg with
        | HeatUp -> return! heating()
        | _ -> return! cooling()}

    // the initial state
    heating()
    )

And post messages to it to change states:

climateControl.Post HeatUp;;
Heating
val it : unit = ()

climateControl.Post CoolDown;;
Cooling
val it : unit = ()

And that’s it! The main points of interest are the states, each defined by a separate function heating() and cooling() – note they are mutually recursive so have to be declared with ‘and’ – and the ‘match’ expression used to change states.

Of course they can get more complicated, but you have the basic pattern. For a more in-depth look at F# actors in general, check out this post by on F# for Fun and Profit.

Happy state transitions!

Advertisements
Categories: F# Tags: ,
  1. Min Chan
    November 29, 2015 at 10:27 pm

    The link to the monad nomad is dead 😐

    • Grant Crofton
      November 30, 2015 at 8:31 am

      Thanks, I’ve changed it to a different link.

  2. September 14, 2016 at 3:57 am

    Never hesitate to suggest your personal favourite games
    in the comment section at the bottom of this page.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: