scala - 当状态满足某些条件时如何停止状态转换?

标签 scala functional-programming scalaz scala-cats

我对 scalaz/cats 还很陌生,并且对 State monad 有疑问(catsscalaz 并不重要)。考虑以下著名的 Stack 示例:

object StateTest {

  type Stack = List[Int]

  def main(args: Array[String]) = {
    println(transition.run(List(1, 2, 3, 4)).value) //(List(4),Some(3))
    println(transition.run(List(1, 2)).value) //(List(),None)

  }

  def transition: State[Stack, Option[Int]] = for {
    _ <- pop
    _ <- pop
    a <- pop
  } yield a

  def pop: State[Stack, Option[Int]] = State {
    case x::xs => (xs, Some(x))
    case Nil => (Nil, None)
  }
}

问题是我想执行状态转换(pop),直到状态(List[Int])满足某些条件(我想检查 List[Int]::isEmpty) 然后立即停止。

在当前的实现中,我只能在调用run后知道状态是否满足条件。

是否可以使用 State monad 在 cats/scalaz 中执行此操作,或者我需要其他东西?

最佳答案

您将使用由代表终止的另一个 monad 参数化的状态 monad。

一般来说,这种参数化的 monad 被称为 monad 转换器。在这种特定情况下,您将使用 StateT monad 转换器。对一些实现细节取模,StateT 相当于

type StateT[F[_], S, A] = S => F[(S, A)]

现在可以选择FOption,代表立即终止。

import scalaz.StateT
import scalaz.std.option._

object StateTest {

  type Stack = List[Int]

  def main(args: Array[String]) = {
    println(transition.run(List(1, 2, 3, 4))) // Some((List(4), 3))
    println(transition.run(List(1, 2)))       // None
  }

  def transition: StateT[Option, Stack, Int] = for {
    _ <- pop
    _ <- pop
    a <- pop
  } yield a

  def pop: StateT[Option, Stack, Int] = StateT {
    case x::xs => Some((xs, x))
    case Nil   => None
  }
}

如果即使在提前终止的情况下也想返回 B 类型的值,则可以使用 Either[B, ?] 而不是 Option 参数化 StateT:

type ErrorOr[A] = Either[String, A]

def pop1: StateT[ErrorOr, Stack, Int] = StateT {
  case x::xs => Right((xs, x))
  case Nil   => Left("Cannot pop from an empty stack.")
}

关于scala - 当状态满足某些条件时如何停止状态转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50573817/

相关文章:

functional-programming - 纯函数自底向上树算法

functional-programming - 在 OCaml 中是否有一种惯用的方法来执行隐式本地状态?

java - 如何在 Java 中链接函数调用?

scala - 根据用户输入停止进程 [Task, O]

scala - 带参数的无形 HList 多态映射

scala - Gatling-Value baseURL 不是 io.gatling.http.protocol.HttpProtocolBuilder 的成员

scala - 创建状态转换以将集合元素添加到 Map[K, Set[V]] 的更好方法

Scala pipelines - 用于构建 DAG 工作流程的 DSL

scala - 在没有错误状态的情况下处理 iteratee 库中的异常

scala - NULL 指针异常,同时在 foreach() 中创建 DF