scala - 当状态满足某些条件时如何停止状态转换?
问题描述
我对 scalaz/cats 很陌生,并且对State
monad 有疑问(cats
或scalaz
无关紧要)。考虑以下众所周知的示例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
。
是否可以在猫/scalaz 中使用 State monad 这样做,或者我需要其他东西?
解决方案
您将使用由另一个表示终止的 monad 参数化的 state monad。
通常,这种参数化的 monad 称为monad 转换器。在这种特定情况下,您将使用StateT
monad 转换器。取模一些实现细节,StateT
相当于
type StateT[F[_], S, A] = S => F[(S, A)]
现在可以选择F
be Option
,代表立即终止。
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.")
}
推荐阅读
- swift - 不通知代币的领域交易
- r - Shiny:使用带有 actionLinks 和 shinyJS 的动态 renderUI
- azure - 逻辑应用与 Azure 租户中的 SQL 数据库通信是否需要集成服务环境?
- javascript - 为什么动态焦点(使用 JavaScript)在 iPad iOS 13+ 中不起作用?
- javascript - 如何仅使用管理员登录。角
- python - 使用 Python 删除文件中的数据
- c# - 搜索开始菜单时应用程序图标不正确
- angular - 在 ngFor 中使用 mat-accordion 和 mat-expansion-panel
- sequelize.js - 如何在续集上过滤关联表或父级
- postgresql - PostgreSQL 中的 FROM_TZ 等效项