在State Monad中使用flatMap的典型方案?

时间:2019-09-19 07:33:23

标签: scala flatmap 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) 
    }
}

2 个答案:

答案 0 :(得分:2)

此引用摘自wikibooks中有关Haskell中的状态monad的信息。

  

如果您以前使用任何其他语言编程,则可能编写了一些“保持状态”的函数。对于那些不熟悉该概念的人来说,状态是一个或多个执行某些计算所需的变量,但不在相关函数的参数之列。像C ++这样的面向对象的语言大量使用状态变量(以类和对象内的成员变量的形式)。另一方面,像C这样的过程语言通常使用在当前作用域之外声明的全局变量来跟踪状态。

  但是,在Haskell中,此类技术并不是那么容易应用。这样做将需要可变的变量,这将意味着函数将具有隐藏的依赖关系,这与Haskell的函数纯度不符。幸运的是,通常可以以功能上纯净的方式跟踪状态。为此,我们将状态信息从一个函数传递到另一个函数,从而使隐藏的依赖关系更加明确。

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

状态monad的最常见示例是:

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

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

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

答案 1 :(得分:2)

根据猫State单子documentation

  

通过flatMap上的State[S, A]方法,您可以使用一个State的结果   在随后的State

这意味着我们可以像这样在理解中很好地排列状态转换

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的目的是链接单子计算,因此无论我们拥有什么单子,我们都可以将其包含在理解范围之内。