Scala 関数型デザイン&プログラミング 6章 Exercise
結構間があいてしまった。
package fpinscala trait RNG { def nextInt: (Int, RNG) } case class SimpleRNG(seed: Long) extends RNG { type Rand[+A] = RNG => (A, RNG) def nextInt: (Int, RNG) = { val newSeed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFFL val nextRNG = SimpleRNG(newSeed) val n = (newSeed >>> 16).toInt (n, nextRNG) } // 6.1 def nonNegativeInt(rng: RNG): (Int, RNG) = { val (n, nextRNG) = rng.nextInt val next = if (n == Int.MinValue) { 0 } else { math.abs(n) } (next, nextRNG) } // 6.2 def double(rng: RNG): (Double, RNG) = { val (n, nextRNG) = nonNegativeInt(rng) val next = n.toDouble / Int.MaxValue.toDouble (next, nextRNG) } // 6.3 def intDouble(rng: RNG): ((Int, Double), RNG) = { val (n1, rng1) = rng.nextInt val (n2, rng2) = double(rng1) ((n1, n2), rng2) } // 6.3 def doubleInt(rng: RNG): ((Double, Int), RNG) = { val (n1, rng1) = double(rng) val (n2, rng2) = rng1.nextInt ((n1, n2), rng2) } // 6.3 def double3(rng: RNG): ((Double, Double, Double), RNG) = { val (n1, rng1) = double(rng) val (n2, rng2) = double(rng1) val (n3, rng3) = double(rng2) ((n1, n2, n3), rng3) } // 6.4 def ints(count: Int)(rng: RNG): (List[Int], RNG) = { if (count > 0) { val (x, rng1) = rng.nextInt val (xs, rng2) = ints(count - 1)(rng1) (x :: xs, rng2) } else { (Nil, rng) } } val int: Rand[Int] = _.nextInt def unit[A](a: A): Rand[A] = rng => (a, rng) def map[A, B](s: Rand[A])(f: A => B): Rand[B] = { rng => val (a, rng2) = s(rng) (f(a), rng2) } // 6.5 def double2: Rand[Double] = map(nonNegativeInt)(i => i.toDouble / Int.MaxValue.toDouble) // 6.6 def map2[A, B, C](ra: Rand[A], rb: Rand[B])(f: (A, B) => C): Rand[C] = { rng => val (a, rng1) = ra(rng) val (b, rng2) = rb(rng1) (f(a, b), rng2) } // 6.7 def sequence[A](fs: List[Rand[A]]): Rand[List[A]] = { rng => fs.foldLeft((Nil: List[A], rng)){ (a, s) => val (xs, rng1) = a val (x, rng2) = s(rng1) (x :: xs, rng2) } } // 6.8 def flatMap[A, B](f: Rand[A])(g: A => Rand[B]): Rand[B] = { rng => val(x, rng1) = f(rng) g(x)(rng1) } // 6.8 def nonNegativeLessThan(n: Int): Rand[Int] = flatMap(nonNegativeInt){ i => val mod = i % n if (i + (n - 1) - mod >= 0) rng => (mod, rng) else nonNegativeLessThan(n) } // 6.9 def mapF[A, B](s: Rand[A])(f: A => B): Rand[B] = { flatMap(s){ a => rng => (f(a), rng) } } // 6.9 def map2F[A, B, C](ra: Rand[A], rb: Rand[B])(f: (A, B) => C) = { flatMap(ra) { a => mapF(rb) { b => f(a, b) } } } } case class State[S, +A](run: S => (A, S)) { // 6.10 def unit[B >: A](b: B): State[S, B] = State(st => (b, st)) // 6.10 def flatMap[B](g: A => State[S, B]): State[S, B] = State { st => { val (a, s) = this.run(st) g(a).run(s) } } // 6.10 def map[B](f: A => B): State[S, B] = { this.flatMap{ a => State(st => (f(a), st)) } } def modify[S](f: S => S): State[S, Unit] = for { s <- get _ <- set(f(s)) } yield () def get[S]: State[S, S] = State(s => (s, s)) def set[S](s: S): State[S, Unit] = State(_ => ((), s)) } object State { // 6.10 def map2[A, B, C, S](sa: State[S, A], sb: State[S, B])(f: (A, B) => C): State[S, C] = { sa.flatMap{ a => sb.map{ b => f(a, b) } } } // 6.10 def sequence[A, S](fs: List[State[S, A]]): State[S, List[A]] = State{ st => def go(s: S, xs: List[State[S, A]]): (List[A], S) = xs match { case Nil => (Nil, s) case y :: ys => { val (n, s1) = y.run(s) val (nx, s2) = go(s1, ys) (n :: nx, s2) } } go(st, fs) } } sealed trait Input case object Coin extends Input case object Turn extends Input case class Machine(locked: Boolean, candies: Int, coins: Int) object Main extends App { def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = State { machine => val res = inputs.foldLeft(machine) { case (a, x) => (a, x) match { case (Machine(_, 0, co), _) => a case (Machine(true, ca, co), Coin) => Machine(false, ca, co + 1) case (Machine(false, ca, co), Turn) => Machine(true, ca - 1, co) case _ => a } } ((res.coins, res.candies), res) } }