在猫中对 StateMonad 进行测序

Sequencing a StateMonad in Cats

我刚刚查看了 scala 中的猫库,更具体地说是 State Monad。

作为玩具示例,我想创建一些逻辑来拆分可能较大的字符串(StringBuilder)和 returns 拆分字符串和剩余的 StringBuilder:

object Splitter {
  def apply(maxSize: Int, overlap: Int): State[StringBuilder, String] = State(
    builder => {
      val splitPoint = math.min(builder.size, maxSize + overlap)
      (builder.drop(maxSize), builder.substring(0, splitPoint))
    }
  )
}

运行 State monad 的一个步骤工作正常,但我想链接所有步骤,直到 StringBuilder 最终为空:

val stop = State.inspect((s: StringBuilder) => s.isEmpty)
Splitter(3, 2).untilM[Vector](stop).run(new StringBuilder("tarsntiars"))

但是,这不起作用,因为直到 M 是 Monad 特征的成员并且范围内没有隐式转换。有效的是:

val monad = StateT.catsDataMonadForStateT[Eval, StringBuilder]
monad.untilM[List, String](Splitter(3, 2))(stop).run(new StringBuilder("tarsntiars"))

但是,我认为较短的版本更具可读性,所以我想知道为什么它不起作用?为什么通常的 MonadOps 机制在这里不起作用?

修复 SI-2712 后,Unapply 解决方法已从 Cats 中移除:https://github.com/typelevel/cats/pull/1583。现在您需要 -Ypartial-unification 编译器标志(假设您使用的是 Scala 2.11 或 2.12),以便 State 被视为 Monad.

Scalaz 仍然具有 Unapply 机制,因此您的代码应该可以在没有编译器标志的情况下使用 Scalaz。