State Monad中使用flatMap的典型场景?

A typical scenario of using flatMap in State Monad?

我看了State Monad的定义如下,其中包含了flatMap的定义。 flatMap 的字面定义对我来说很清楚,但是它的典型用例是什么?

trait State[S,A]{
  def run (initial:S):(S,A)
  def flatMap[B] (f:A=>State[S,B]):State[S,B] = 
    State{ s =>
      val (s1, a) = run(s)
      f(a).run(s1)
    }
}

object State{
  def apply[S,A](f:S => (S,A)):State[S,A] =
    new State[S,A] {
        def run(initial:S): (S,A) = f(initial) 
    }
}

这句话摘自 wikibooks 关于 haskell 中的 state monad。

If you have programmed in any other language before, you likely wrote some functions that "kept state". For those new to the concept, a state is one or more variables that are required to perform some computation but are not among the arguments of the relevant function. Object-oriented languages like C++ make extensive use of state variables (in the form of member variables inside classes and objects). Procedural languages like C on the other hand typically use global variables declared outside the current scope to keep track of state.

In Haskell, however, such techniques are not as straightforward to apply. Doing so will require mutable variables which would mean that functions will have hidden dependencies, which is at odds with Haskell's functional purity. Fortunately, often it is possible to keep track of state in a functionally pure way. We do so by passing the state information from one function to the next, thus making the hidden dependencies explicit.

基本上它的目的是编写操作状态的纯函数程序,让 API 计算下一个状态而不是实际改变任何东西。

状态 monad 的最常见示例是:

  1. .
  2. Building games
  3. Parsers
  4. Data Stuctures
  5. 任何有限状态机程序。

您还可以查看 cats page for the state monad

注意:还有一个更复杂的状态 monad,称为 IndexedState monad,它基本上为您提供了更改状态的选项。

根据猫 State monad documentation

The flatMap method on State[S, A] lets you use the result of one State in a subsequent State

这意味着我们可以在 for-comprehension 中很好地排列状态转换,就像这样

val createRobot: State[Seed, Robot] =
  for {
    id <- nextLong
    sentient <- nextBoolean
    isCatherine <- nextBoolean
    name = if (isCatherine) "Catherine" else "Carlos"
    isReplicant <- nextBoolean
    model = if (isReplicant) "replicant" else "borg"
  } yield Robot(id, sentient, name, model)

一般来说,flatMap 的目的是链接 monadic 计算,所以无论我们有什么 monad,我们都可以将它放在 for-comprehension 中。