Skip to content

Instantly share code, notes, and snippets.

@bpk-t
Last active August 29, 2015 14:25
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 bpk-t/b18482afbc93b2216eaf to your computer and use it in GitHub Desktop.
Save bpk-t/b18482afbc93b2216eaf to your computer and use it in GitHub Desktop.
FP in Scala Exercise 6.1 -6.11
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