FP in Scala Exercise 6.1 -6.11
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package FPinScalaExercise6 | |
/** | |
* Created by BPK_t on 2015/07/20. | |
*/ | |
object Main { | |
def main(args: Array[String]) { | |
val rng = SimpleRng(42) | |
val (n1, rng2) = rng.nextInt | |
println(n1) | |
val (n2, rng3) = rng2.nextInt | |
println(n2) | |
println(nonNegativeInt(rng3)) | |
val ((d1,d2,d3),rng4) = double3(rng3) | |
println(s"$d1, $d2, $d3") | |
println(ints(5)(rng4)) | |
val (dm, rng5) = doubleM(rng4) | |
println(dm) | |
println(intsS(5)(rng5)) | |
} | |
//6.1 | |
def nonNegativeInt(rng : RNG) : (Int, RNG) = | |
rng.nextInt match { | |
case (n, nextRng) => if (n < 0) {(((n + 1) * -1), nextRng)} else {(n, nextRng)} | |
} | |
//6.2 | |
def double(rng : RNG) : (Double, RNG) = | |
rng.nextInt match { | |
case (x, nextRng) => (x.toDouble / 10000000000.0, nextRng) | |
} | |
//6.3-1 | |
def intDouble(rng : RNG) : ((Int, Double), RNG) = { | |
val (i, rng2) = rng.nextInt | |
val (d, rng3) = double(rng2) | |
((i,d), rng3) | |
} | |
//6.3-2 | |
def doubleInt(rng : RNG) : ((Double, Int), RNG) = { | |
val ((i, d), rng2) = intDouble(rng) | |
((d, i), rng2) | |
} | |
//6.3-3 | |
def double3(rng : RNG) : ((Double, Double, Double), RNG) = { | |
double(rng) match { | |
case (d, rng2) => double(rng2) match { | |
case (d2, rng3) => double(rng3) match { | |
case (d3, rng4) => ((d, d2, d3), rng4) | |
} | |
} | |
} | |
} | |
//6.4 | |
def ints(count : Int)(rng : RNG) : (List[Int], RNG) = { | |
if (count <= 0) { | |
(Nil, rng) | |
} else { | |
val (n, rng2) = rng.nextInt | |
val (list, rng3) = ints(count - 1)(rng2) | |
(n :: list, rng3) | |
} | |
} | |
type 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) | |
} | |
val int : Rand[Int] = _.nextInt | |
//6.5 | |
def doubleM : Rand[Double] = | |
map(int)(x => x.toDouble / 10000000000.0) | |
//6.6 | |
def map2[A,B,C](ra : Rand[A], rb : Rand[B])(f : (A, B) => C) : Rand[C] = rng => { | |
val (a, rng2) = ra(rng) | |
val (b, rng3) = rb(rng2) | |
(f(a, b), rng3) | |
} | |
def both[A,B](ra : Rand[A], rb : Rand[B]) : Rand[(A,B)] = | |
map2(ra, rb)((_, _)) | |
val randIntDouble : Rand[(Int, Double)] = both(int, double) | |
val randDoubleInt : Rand[(Double, Int)] = both(double, int) | |
//6.7 | |
def sequence[A](fs : List[Rand[A]]) : Rand[List[A]] = rng => sequence_(fs, Nil, rng) | |
private def sequence_[A](fs : List[Rand[A]], outList : List[A], nextRng: RNG) : (List[A], RNG) = { | |
fs match { | |
case Nil => (outList, nextRng) | |
case (h::t) => h(nextRng) match { | |
case (a,r) => sequence_(t, outList:+a, r) | |
} | |
} | |
} | |
//6.7 | |
def intsS(count : Int) : Rand[List[Int]] = rng => | |
sequence(List.fill(count)(int))(rng) | |
//6.8 | |
def flatMap[A,B](f : Rand[A])(g : A=>Rand[B]):Rand[B] = | |
rng => { | |
f(rng) match { | |
case (a, rng2) => g(a)(rng2) | |
} | |
} | |
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-1 | |
def mapF[A,B](s : Rand[A])(f : A => B) : Rand[B] = | |
flatMap(s)(x => rng => (f(x),rng)) | |
//6.9-2 | |
def map2F[A,B,C](ra : Rand[A], rb : Rand[B])(f : (A, B) => C) : Rand[C] = | |
flatMap(ra)(x => flatMap(rb)(y => rng => (f(x, y), rng))) | |
//type State[S, +A] = S => (A, S) | |
} | |
trait RNG { | |
def nextInt : (Int, RNG) | |
} | |
case class SimpleRng(seed : Long) extends RNG { | |
def nextInt : (Int, RNG) = { | |
val newSeed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFFL | |
val nextRNG = SimpleRng(newSeed) | |
val n = (newSeed >> 16).toInt | |
(n, nextRNG) | |
} | |
} | |
case class State[S, +A](run : S => (A, S)) | |
{ | |
//unit, map, map2, flatMap, sequence | |
//6.10 | |
def map[B](f : A => B) : State[S, B] = | |
this match { | |
case State(r) => State(x => r(x) match {case (a, s) => (f(a), s)}) | |
} | |
//6.10 | |
def map2[B,C](s2 : State[S, B])(f : (A, B) => C) : State[S,C] = | |
this match { | |
case State(r) => State(x => r(x) match {case (a, s) => s2 match {case State(r2) => r2(s) match {case (b, s2) => (f(a, b), s2)}}}) | |
} | |
//6.10 | |
def flatMap[B](f : A => State[S, B]) : State[S, B] = | |
this match { | |
case State(r) => State(x => r(x) match {case (a, s) => f(a).run(s)}) | |
} | |
} | |
object State { | |
//6.10 | |
def sequence[S,B](fs : List[State[S, B]]) : State[S, List[B]] = State(s => sequence_(fs, Nil, s)) | |
private def sequence_[S,B](fs : List[State[S, B]], outList : List[B], nextS: S) : (List[B], S) = { | |
fs match { | |
case Nil => (outList, nextS) | |
case (h::t) => h match { | |
case State(r) => r(nextS) match { | |
case (a,s) => sequence_(t, outList:+a, s) | |
} | |
} | |
} | |
} | |
} | |
//6.11 | |
sealed trait Input | |
//硬化を投入する(locked = false, coins++) | |
case object Coin extends Input | |
//ロックが解除された状態の自動販売機のハンドルを回す(candies--) | |
case object Turn extends Input | |
//自動販売機の状態 | |
case class Machine(locked : Boolean, candies : Int, coins : Int) | |
object Simulator { | |
//(硬貨、スナック) | |
def simulateMachine(inputs : List[Input]) : State[Machine, (Int, Int)] = | |
State(x => | |
State.sequence( | |
inputs.map(input => input match { | |
case Coin => State[Machine, Unit](prevMachine => | |
if (prevMachine.candies <= 0) ((), prevMachine) | |
else ((), Machine(false, prevMachine.candies, prevMachine.coins + 1))) | |
case Turn => State[Machine, Unit](prevMachine => | |
if (prevMachine.candies <= 0 || prevMachine.locked) ((), prevMachine) | |
else ((), Machine(true, prevMachine.candies - 1, prevMachine.coins))) | |
}) | |
).run(x) match { | |
case (_, s) => ((s.coins, s.candies), s) | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment