Skip to content

Instantly share code, notes, and snippets.

@adamrabung
Created September 22, 2014 16:11
Show Gist options
  • Save adamrabung/e2b44f950c0b148cf5e5 to your computer and use it in GitHub Desktop.
Save adamrabung/e2b44f950c0b148cf5e5 to your computer and use it in GitHub Desktop.
import State._
case class State[S, +A](run: S => (A, S)) {
def map[B](f: A => B): State[S, B] = flatMap(a => unit(f(a)))
def map2[B, C](sb: State[S, B])(f: (A, B) => C): State[S, C] = flatMap(a => sb.map(b => f(a, b)))
def flatMap[B](f: A => State[S, B]): State[S, B] = State(s => {
val (a, s1) = run(s)
f(a).run(s1)
})
}
object State {
def unit[S, A](a: A): State[S, A] = State(s => (a, s))
def sequence[S, A](sas: List[State[S, A]]): State[S, List[A]] = {
def go(s: S, actions: List[State[S, A]], acc: List[A]): (List[A], S) =
actions match {
case Nil => (acc.reverse, s)
case h :: t => h.run(s) match { case (a, s2) => go(s2, t, a :: acc) }
}
State((s: S) => go(s, sas, List()))
}
}
sealed trait Input
case object Coin extends Input
case object Turn extends Input
case class Machine(locked: Boolean, candies: Int, coins: Int)
object CandyMachineEvents {
def apply(events: List[Input]) = sequence(events.map(createState))
//Create a new machine instance based on the event, and creates a new State to represent it
def createState(event: Input): State[Machine, Unit] = State(run = m => ((), runEvent(m, event)))
def runEvent(m: Machine, event: Input): Machine = (event, m) match {
case (_, machine) if machine.candies == 0 => m
case (Coin, machine) if !machine.locked => m
case (Turn, machine) if machine.locked => m
case (Coin, Machine(true, candy, coin)) => Machine(false, candy, coin + 1)
case (Turn, Machine(false, candy, coin)) => Machine(true, candy - 1, coin)
}
}
object RunSimulation extends App {
val candyMachine = Machine(locked = true, candies = 3, coins = 10)
val events: State[Machine, List[Unit]] = CandyMachineEvents(events = List(Coin, Turn, Coin, Turn, Turn))
events.run(candyMachine) match {
case (_, machine) => println(s"11:40:18 AM candies = ${machine.candies} coins = ${machine.coins}")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment