Archive

Archive for July, 2013

Making a simple State Machine with F# Actors

July 30, 2013 3 comments

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!

Categories: F# Tags: ,