在 Scala 中获取和设置状态
Getting and setting state in scala
以下是《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
方法看起来像它们的样子,但我就是不明白。
请问谁能赐教吗?
关键在第三行:
case class State[S, +A](run: S => (A, S))
状态计算用run
函数表示。此函数表示从一种状态 S
到另一种状态 S
的转换。 A
是我们从一种状态移动到另一种状态时可以产生的值。
现在,我们如何从 state-monad 中取出状态 S
?我们可以进行不进入不同状态的转换,并且我们使用函数 s => (s, s)
:
将状态具体化为 A
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)
必须是由 flatmap
步骤的 A
组成的三元组 (<-
).
我们说 get
"fill" 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
以下是《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
方法看起来像它们的样子,但我就是不明白。
请问谁能赐教吗?
关键在第三行:
case class State[S, +A](run: S => (A, S))
状态计算用run
函数表示。此函数表示从一种状态 S
到另一种状态 S
的转换。 A
是我们从一种状态移动到另一种状态时可以产生的值。
现在,我们如何从 state-monad 中取出状态 S
?我们可以进行不进入不同状态的转换,并且我们使用函数 s => (s, s)
:
A
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)
必须是由 flatmap
步骤的 A
组成的三元组 (<-
).
我们说 get
"fill" 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