在scala中获取和设置状态

在scala中获取和设置状态,scala,functional-programming,state,Scala,Functional Programming,State,下面是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] = flatMa

下面是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))
  }
导入状态_
案例类状态[S,+A](运行:S=>(A,S)){
def映射[B](f:A=>B):状态[S,B]=
平面图(a=>单位(f(a)))
defmap2[B,C](sb:状态[S,B])(f:(A,B)=>C):状态[S,C]=
平面图(a=>sb.map(b=>f(a,b)))
def flatMap[B](f:A=>状态[S,B]):状态[S,B]=状态(S=>{
val(a,s1)=运行(s)
f(a).运行(s1)
})
}
对象状态{
类型Rand[A]=状态[RNG,A]
def单位[S,A](A:A):状态[S,A]=
州(s=>(a,s))
//惯用的解决方案是通过foldRight表达的
def sequenceViaFoldRight[S,A](sas:List[State[S,A]]):State[S,List[A]]=
sas.foldRight(单位[S,列表[A]](列表.empty[A])((f,acc)=>f.map2(acc)()
//此实现在内部使用循环,并且是相同的递归
//图案为左折。建造左折非常常见
//将列表按相反顺序排列,然后在末尾将其反转。
//(我们也可以在内部使用collection.mutable.ListBuffer。)
def序列[S,A](sas:List[State[S,A]]):State[S,List[A]={
def go(s:s,动作:列表[状态[s,A]],acc:List[A]):(列表[A],s)=
动作匹配{
案例无=>(附件反向,s)
案例h::t=>h.run(s)匹配{
案例(a,s2)=>go(s2,t,a::acc)
}
}
状态((s:s)=>go(s,sas,List())
}
//我们也可以使用左折叠编写循环
//以前的解决方案,但它在折叠列表之前而不是之后反转列表。
//您可能认为这比“foldRight”解决方案慢,因为它
//浏览列表两次,但实际上速度更快!foldRight解决方案
//从技术上讲,我们还必须在名单上浏览两次,因为它必须解开电话
//堆栈,而不是尾部递归。调用堆栈将与列表一样高
//它很长。
def sequenceViaFoldLeft[S,A](l:List[State[S,A]]):State[S,List[A]]=
l、 反向折叠(单位[S,List[A]](List())((acc,f)=>f.map2(acc)()
def modify[S](f:S=>S):状态[S,单位]=用于{
s((),s))
}
我花了几个小时思考为什么
get
set
方法看起来像这样,但我就是不明白


有人能告诉我吗?

钥匙在第三行:

case class State[S, +A](run: S => (A, S))
有状态计算用
run
函数表示。此函数表示从一个状态
S
到另一个状态的转换
S
a
是我们从一个状态移动到另一个状态时可能产生的值

现在,我们如何才能将状态
S
从状态monad中移除?我们可以进行一个不会转到不同状态的转换,并使用函数
S=>(S,S)
将状态具体化为
a

如何设置状态?我们所需要的只是一个函数,它将进入状态s:
???=>(???,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)
要使用组合的
statefullcomputions
,我们需要
运行它:

statefullComputationsCombined.run(1)._1 == (1,10,100)
如果我们想要计算结束时的状态:

statefullComputationsCombined.run(1)._2 == 100

钥匙在第三行:

case class State[S, +A](run: S => (A, S))
有状态计算用
run
函数表示。此函数表示从一个状态
S
到另一个状态的转换
S
a
是我们从一个状态移动到另一个状态时可能产生的值

现在,我们如何才能将状态
S
从状态monad中移除?我们可以进行一个不会转到不同状态的转换,并使用函数
S=>(S,S)
将状态具体化为
a

如何设置状态?我们所需要的只是一个函数,它将进入状态s:
???=>(???,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)
要使用组合的
statefullcomputions
,我们需要
运行它:

statefullComputationsCombined.run(1)._1 == (1,10,100)
如果我们想要计算结束时的状态:

statefullComputationsCombined.run(1)._2 == 100

示例添加。希望它进一步澄清示例添加。希望它进一步澄清