scala関数式プログラミングノート:純関数式状態
5657 ワード
scala関数式プログラミング:純関数式状態読書ノート
Overview:ステータス付きメソッドの宣言式実装は副作用がある可能性があり、参照の透明性を保つことは困難である. 純粋な関数式で状態付き関数を実現する鍵は,状態更新を明示的にし,副作用的に状態を更新するのではなく,生成した値とともに新しい状態を返すことにある.すなわち,状態の暗黙的な変更を暴露する. 例:関数nextIntは変更後の新状態nextRNGを返す
コンボ:アセンブリは高次関数であり、表示されないように状態伝達を行うための関数のタイプ別名と見なすことができる. RNG=>(A,RNG)は、古いRNGを受け入れて新しいRNGを得る関数であり、状態挙動は、組合せ子Rand: 実例分析: そして
状態の動作を組み合わせるには、コンボを使用します.状態のある関数については、まずそのパラメータと戻り値を組み合わせ子としてパッケージする.そしてmap,flatMap等により純粋な関数として実現する.ここでf,gなどがこの関数である. 状態挙動:s(rng 1:RNG)戻り(v:Int,rng 2:RNG) 2つの状態行動を組み合わせる: シーケンス状態挙動の組み合わせ:
汎用状態動作データ型前合成子状態がタイプRNGである.コンビネーションを汎化しましょう.Sは任意の状態を表す. 汎化した組合せ子を1つのclassと定義することもできる.State[+A,S]で定義された関数は、関数スタイルの任意のステートマシンまたはステータスプログラムを実現するために必要なすべてのツールです.
インスタンスの適用タイトル EXERCISE 13 (hard): To gain experience with the use of State, implement a simulation of a simple candy dispenser. The machine has two types of input: You can insert a coin, or you can turn the knob to dispense candy. It can be in one of two states: locked or unlocked. It also tracks how many candies are left and how many coins it contains.
[外部チェーン画像の転送に失敗しました(img-Amx 9 zUg-1564306192450)(http://oxaz2p2ac.bkt.clouddn.com/Screen Shot 2017-10-04 at 10.21.02 PM.png)]標準回答:https://github.com/fpinscala/fpinscala/blob/master/answerkey/state/11.answer.scala 私の解法:https://github.com/haiboself/Scala-learning/tree/master/src/PureFunctionalState 参考資料: https://stackoverflow.com/questions/41012375/functional-programing-in-scala-simulatemachine/41328969#41328969 https://groups.google.com/forum/#!topic/scala-functional/8iHaSFPPjgw
Overview:
trait RNG{
def nextInt: (Int,RNG)
}
case class SimpleRNG(seed: Long) extends RNG{
// Int , , SimpleRNG
def nextInt: (Int,RNG) = {
val newSeed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFL
val nextRNG = SimpleRNG(newSeed)
val n = (newSeed >>> 16).toInt
(n, nextRNG)
}
// ,currentSeed
val currentSeed = seed
def nextInt2: Int = {
val newSeed = (currentTime * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFL
currentSeed = newSeed
val n = (newSeed >>> 16).toInt
n
}
}
コンボ:
type Rand[+A] = RNG => (A, RNG)
val int: Rand[Int] = _.nextInt
_.nextInt RNG => (Int,RNG)
.すなわち、RNGタイプパラメータを受け入れ、(Int,RNG)タイプメタグループの関数を返す.Rand[Int]
は関数RNG => (Int,RNG)
のタイプ別名です.状態の動作を組み合わせるには、コンボを使用します.
def map[A,B](s: Rand[A])(f: A => B): Rand[B] =
rng1 => {
val (v,rng2) = s(rng1)
(f(v),rng2)
}
def flatMap[A,B](f: Rand[A)(g: A => Rand[B]): Rand[B] =
rng => {
(v,r) = f(rng)
g(v)(r)
}
def map2[A,B,C](ra: Rand[A], rb: Rand[B])(f: (A,B) => C): Rand[c] =
rng1 => {
val (v1,rng2) = ra(rng1)
val (v2,rng3) = rb(rng2)
(f(v1,v2),rng3)
}
def unit[A](a: A): Rand[A] = rng => (a,rng)
def sequence[A](fs: List[Rand[A]]): Rand[List[A]] =
List.foldRight(fs,unit(List[A())))((x,y) => map2(x,y)((a,b) => Cons(a,b)))
汎用状態動作データ型
type State[+A,S] = S => (A,S)
case class State[+A,S](run: S => (A,S)) extends AnyVal{
def map[B](f: A => B): State[B,S] = State(
s => {
val (i,r) = run(s)
(f(i),r)
})
def map2[B,C](b: State[B,S])(f: (A,B) => C): State[C,S] = State(
s => {
val (v1,s1) = run(s)
val (v2,s2) = b.run(s1)
(f(v1,v2),s2)
})
//def _map2[B,C](b: State[B,S])(f: (A,B) => C): State[C,S] =
// flatMap(x => b.map(y => f((x,y))))
def flatMap[B](f: A => State[B,S]): State[B,S] = State(
s => {
val (v,s1) = run(s)
f(v).run(s1)
})
}
object State{
def unit[A,S](x: A): State[A,S] = State(s => (x,s))
def sequence[A,S](ls: List[State[A,S]]): State[List[A],S] =
List.foldRight(ls,unit[List[A],S](List()))((x,y) => x.map2(y)(Cons(_,_)))
def modify[S](f: S => S): State[Unit,S] = for {
s (s,s))
def set[S](s: S): State[Unit,S] = State(_ => ((), s))
}
インスタンスの適用
[外部チェーン画像の転送に失敗しました(img-Amx 9 zUg-1564306192450)(http://oxaz2p2ac.bkt.clouddn.com/Screen Shot 2017-10-04 at 10.21.02 PM.png)]
package PureFunctionalState
import datastruct._
sealed trait Input
case object Coin extends Input
case object Turn extends Input
case class Machine(locked: Boolean, candies: Int, coins: Int) {
/**
* Machine , Machine
*
*/
def simulateMachine(inputs: List[Input]): Machine = {
List.foldLeft(inputs,Machine(locked,candies,coins))((x, y) => (x,y) match {
case (Coin,Machine(true,cands,x)) if cands>0 => Machine(false,cands,x)
case (Turn,Machine(false,cands,x)) if cands>0 => Machine(true,cands-1,x+1)
case _ => y
}
)
}
/** 。
* modify State[Unit,Machine]。modify , inputs Machine
* map List[State[Unit,Machine]]
* sequence State[List[Unit],Machine]
*/
def simulateMachine3(inputs: List[Input]): State[(Int, Int),Machine] = for {
_ State.modify((s: Machine) => (i, s) match {
case (_, Machine(_, 0, _)) => s
case (Coin, Machine(false, _, _)) => s
case (Turn, Machine(true, _, _)) => s
case (Coin, Machine(true, candy, coin)) =>
Machine(false, candy, coin + 1)
case (Turn, Machine(false, candy, coin)) =>
Machine(true, candy - 1, coin)
})))
s