以下是Scala中函数式编程的一些代码:
import State._ case class State[S, +A](run: S => (A, S)) { def map[B](f: A => B): State[S, B] = flatMap(a => unit(f(a))) def map2[B, C](sb: State[S, B])(f: (A, B) => C): State[S, C] = flatMap(a => sb.map(b => f(a, b))) def flatMap[B](f: A => State[S, B]): State[S, B] = State(s => { val (a, s1) = run(s) f(a).run(s1) }) } object State { type Rand[A] = State[RNG, A] def unit[S, A](a: A): State[S, A] = State(s => (a, s)) // The idiomatic solution is expressed via foldRight def sequenceViaFoldRight[S, A](sas: List[State[S, A]]): State[S, List[A]] = sas.foldRight(unit[S, List[A]](List.empty[A]))((f, acc) => f.map2(acc)(_ :: _)) // This implementation uses a loop internally and is the same recursion // pattern as a left fold. It is quite common with left folds to build // up a list in reverse order, then reverse it at the end. // (We could also use a collection.mutable.ListBuffer internally.) def sequence[S, A](sas: List[State[S, A]]): State[S, List[A]] = { def go(s: S, actions: List[State[S, A]], acc: List[A]): (List[A], S) = actions match { case Nil => (acc.reverse, s) case h :: t => h.run(s) match { case (a, s2) => go(s2, t, a :: acc) } } State((s: S) => go(s, sas, List())) } // We can also write the loop using a left fold. This is tail recursive like the // previous solution, but it reverses the list _before_ folding it instead of after. // You might think that this is slower than the `foldRight` solution since it // walks over the list twice, but it's actually faster! The `foldRight` solution // technically has to also walk the list twice, since it has to unravel the call // stack, not being tail recursive. And the call stack will be as tall as the list // is long. def sequenceViaFoldLeft[S, A](l: List[State[S, A]]): State[S, List[A]] = l.reverse.foldLeft(unit[S, List[A]](List()))((acc, f) => f.map2(acc)(_ :: _)) def modify[S](f: S => S): State[S, Unit] = for { s <- get // Gets the current state and assigns it to `s`. _ <- set(f(s)) // Sets the new state to `f` applied to `s`. } yield () def get[S]: State[S, S] = State(s => (s, s)) def set[S](s: S): State[S, Unit] = State(_ => ((), s)) }
我花了几个小时思考为什么get
和set
方法看起来像他们一样,但我只是不明白.
有人可以开导我吗?
关键是在第3行:
case class State[S, +A](run: S => (A, S))
有状态计算用run
函数表示.此函数表示从一个状态S
到另一个状态的转换S
.A
是从一个状态移动到另一个状态时我们可以产生的值.
现在,我们怎样才能让国家S
脱离国家一元?我们可以进行不转换到不同状态的转换,并且我们A
将函数实现为状态s => (s, s)
:
def get[S]: State[S, S] = State(s => (s, s))
如何设置状态?我们所需要的只是一个进入状态s的函数??? => (???, s)
:
def set[S](s: S): State[S, Unit] = State(_ => ((), s))
编辑我想添加一个示例来查看get
和执行set
:
val statefullComputationsCombined = for { a <- State.get[Int] b <- State.set(10) c <- State.get[Int] d <- State.set(100) e <- State.get[Int] } yield (a, c, e)
没有进一步了解这个答案,那是什么类型的statefullComputationsCombined
?
一定是State[S, A]
对的吗?S
是Int
什么类型但是什么A
?因为我们屈服(a, c, e)
必须是由步骤()的A
s组成的3元组.flatmap
<-
我们说get
"填充" A
状态S
所以a, c ,d
类型S
,所以Int
.b, d
是Unit
因为def set[S](s: S): State[S, Unit]
.
val statefullComputationsCombined: State[Int, (Int, Int, Int)] = for ...
要使用statefullComputationsCombined
我们需要run
它:
statefullComputationsCombined.run(1)._1 == (1,10,100)
如果我们想要计算结束时的状态:
statefullComputationsCombined.run(1)._2 == 100