Skip to content

Instantly share code, notes, and snippets.

@MiloszKrajewski
Created June 26, 2016 23:19
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save MiloszKrajewski/b0a2668ab10d8b567b89b1b078c02a2f to your computer and use it in GitHub Desktop.
Save MiloszKrajewski/b0a2668ab10d8b567b89b1b078c02a2f to your computer and use it in GitHub Desktop.
State Machine Construction Kit in F#
module StateMachine =
type State<'Event> =
| Next of ('Event -> State<'Event>)
| Stop
let feed state event =
match state with
| Stop -> failwith "Terminal state reached"
| Next handler -> event |> handler
type StateMachine<'event>(initial: State<'event>) =
let mutable current = initial
member this.Fire event = current <- feed current event
member this.IsStopped
with get () = match current with | Stop -> true | _ -> false
let createMachine initial = StateMachine(initial)
let createAgent initial =
MailboxProcessor.Start (fun inbox ->
let rec loop state = async {
let! event = inbox.Receive ()
match event |> feed state with
| Stop -> ()
| Next _ as next -> return! loop next
}
loop initial
)
module DoorMachine =
open StateMachine
type Event = | Open | Close | Lock | Unlock
let configureDoor sound =
let rec opened event =
match event with
| Close -> sound "bang"; Next (closed false)
| Lock -> sound "clack"; Next opened
| _ -> Next opened
and closed locked event =
match event with
| Open when locked -> sound "dumdum"; Next (closed locked)
| Open -> sound "squeak"; Next opened
| Lock -> sound "click"; Next (closed true)
| Unlock -> sound "clack"; Next (closed false)
| _ -> Next (closed locked)
Next (closed false)
let test sound =
let agent = sound |> configureDoor |> StateMachine.createAgent
agent.Post Lock
agent.Post Unlock
agent.Post Open
agent.Post Close
[<EntryPoint>]
let main argv =
DoorMachine.test (printfn "%s")
System.Console.ReadLine() |> ignore
0 // return an integer exit code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment