Skip to content

Instantly share code, notes, and snippets.

@seraphr
Created July 13, 2015 19:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seraphr/d6ec32d7ebd3a4711a97 to your computer and use it in GitHub Desktop.
Save seraphr/d6ec32d7ebd3a4711a97 to your computer and use it in GitHub Desktop.
fp in scala EXERCISE 6.11 CandyMachineの実装
case class State[S, +A](run: S => (A, S)) {
def map[B](f: A => B): State[S, B] = State { s0 =>
val (a, s1) = run(s0)
(f(a), s1)
}
def map2[B, C](that: State[S, B])(f: (A, B) => C): State[S, C] = State { s0 =>
val (a, s1) = this.run(s0)
val (b, s2) = that.run(s1)
(f(a, b), s2)
}
def flatMap[B](f: A => State[S, B]): State[S, B] = State { s0 =>
val (a, s1) = run(s0)
f(a).run(s1)
}
}
object State {
def unit[S, A](a: A) = State[S, A](s => (a, s))
def sequence[S, A](aList: List[State[S, A]]): State[S, List[A]] = aList match {
case x :: xs => x.map2(sequence(xs))(_ :: _)
case _ => unit[S, List[A]](Nil)
}
}
sealed trait Input
case object Coin extends Input
case object Turn extends Input
case class Machine(locked: Boolean, candies: Int, coins: Int)
object CandyMachine {
def coin: State[Machine, Unit] = State {
case m@Machine(_, 0, _) => ((), m)
case m@Machine(false, _, _) => ((), m)
case Machine(true, n, c) => ((), Machine(false, n, c+1))
}
def turn: State[Machine, Unit] = State {
case m@Machine(_, 0, _) => ((), m)
case m@Machine(true, _, _) => ((), m)
case Machine(false, n, c) => ((), Machine(true, n-1, c))
}
def input(i: Input) = if(i == Coin) coin else turn
def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = State{ m0 =>
val (_, m) = State.sequence(inputs.map(input)).run(m0)
((m.coins, m.candies), m)
}
}
val tInitMachine = Machine(true, 5, 10)
val tInputs = List.fill(4)(List(Coin, Turn)).flatten
CandyMachine.simulateMachine(tInputs).run(tInitMachine)._1.ensuring(_ == (14, 1))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment