Skip to content

Instantly share code, notes, and snippets.

@krishnabhargav
Last active June 29, 2016 19:05
Show Gist options
  • Save krishnabhargav/249f77d90ee1a47bebce5d7f3bb647bb to your computer and use it in GitHub Desktop.
Save krishnabhargav/249f77d90ee1a47bebce5d7f3bb647bb to your computer and use it in GitHub Desktop.
type State<'S,'a> = 'S -> ('a * 'S)
module State =
let unit a : State<_,_> = fun s -> (a, s)
let map<'s,'a,'b> (f : 'a -> 'b) (r : State<'s,'a>) =
fun s ->
let a,next = r(s)
f(a), next
let map2<'s,'a,'b,'c> (f : 'a -> 'b -> 'c) (ra : State<'s,'a>) (rb : State<'s,'b>) =
fun s ->
let a, next = ra (s)
let b, next = rb (next)
(f a b), next
let sequence<'s,'a> (rs : State<'s,'a> list) : (State<'s, 'a list>) =
(fun s ->
List.fold (fun (c,st) r ->
let x, nxt = r st
(x::c, nxt)) ([],s) rs)
|> map (List.rev)
let bind<'s,'a,'b> (f : 'a -> State<'s,'b>) (r : State<'s,'a>) : State<'s,'b> =
fun s -> s |> r ||> f
module CandyDispenser =
type Input =
| Coin
| Turn
type Machine = { locked: bool; candies : int; coins: int}
(** RULES **)
(*
The rules of the machine are as follows:
 Inserting a coin into a locked machine will cause it to unlock if there’s any candy left.
 Turning the knob on an unlocked machine will cause it to dispense candy and become locked.
 Turning the knob on a locked machine or inserting a coin into an unlocked machine does nothing.
 A machine that’s out of candy ignores all inputs.
*)
let simulateMachine (inputs: Input list) : State<Machine, (int * int)> =
let handle input : State<Machine, (int*int)> =
fun m ->
match input with
| Input.Coin when m.candies > 0 ->
(m.candies, m.coins + 1), { m with locked = false; coins = m.coins + 1}
| Input.Turn when m.locked |> not ->
(m.candies - 1, m.coins), { m with locked = true; candies = m.candies - 1}
| _ ->
(m.candies, m.coins), m
let sequenced =
inputs
|> List.map (handle)
|> State.sequence
(sequenced |> State.map (List.head))
//buy
let buy = [Input.Coin; Input.Turn] |> simulateMachine
let machine : CandyDispenser.Machine = { candies = 5; coins = 10; locked = true }
//let res, machine = machine |> CandyDispenser.buy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment