Skip to content

Instantly share code, notes, and snippets.

@MiloszKrajewski
Created June 26, 2016 23:19
Show Gist options
  • Select an option

  • Save MiloszKrajewski/b0a2668ab10d8b567b89b1b078c02a2f to your computer and use it in GitHub Desktop.

Select an option

Save MiloszKrajewski/b0a2668ab10d8b567b89b1b078c02a2f to your computer and use it in GitHub Desktop.

Revisions

  1. MiloszKrajewski created this gist Jun 26, 2016.
    61 changes: 61 additions & 0 deletions StateMachine.fs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,61 @@
    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