有一些库可用于执行您所描述的“mtl 样式”状态传递。 (检查这个sn-p之后的类型签名)
import cats._
import cats.data._
import cats.implicits._
// Given an element and state, calculate next state and return value
def modifyEntry(currentElement: Int): State[Option[Int], Option[Int]] = for {
previousElement <- State.get
_ <- State.set[Option[Int]](Some(currentElement)) // Next State
} yield previousElement map (currentElement - _) // Calculated Value
// It is useful for hiding state and passing it implicitly
val result =
for {
val1 <- modifyEntry(1)
val2 <- modifyEntry(2)
val3 <- modifyEntry(3)
// Final state is implicittly stored in the yielded State[Option[Int], Seq[Option[Int]]]
} yield Seq(val1, val2, val3)
// Run with None initial State and coerce evaluation (cats is lazy by default)
println("for-comprehension result (final state and value): " -> result.run(None).value)
// More importantly, it is _easy_ to compose with Traversables or other generic cats traits
println("traverse result (only value): " ->
List(1,2,3).traverse(modifyEntry).runA(None).value) // List(None, Some(1), Some(1))
println("traverse result (only value): " ->
List(1,4,3).traverse(modifyEntry).runA(None).value) // List(None, Some(3), Some(-1))
您会对来自scalaz 的StateFunctions 特征或来自cats 的State 特别感兴趣。对比:https://github.com/fosskers/scalaz-and-cats
Scalaz 状态函数:
trait StateFunctions extends IndexedStateFunctions {
// ...
def get[S]: State[S, S] = State(s => (s, s))
def put[S](s: S): State[S, Unit] = State(_ => (s, ()))
// ...
}
经过一些修改的 Cats StateFunctions:
abstract private[data] class StateFunctions {
// ...
def get[S]: State[S, S] = ??? // Some other code like State(s => (s, s))
def set[S](s: S): State[S, Unit] = State(_ => (s, ()))
}
对于猫,请查看带有其他示例的优秀文档:https://typelevel.org/cats/datatypes/state.html
对于 scalaz,这里有一个关于 Scala 和 Scalaz 中“mtl-style”概述的精彩演讲:Paweł Szulc - GETTING MORE MILEAGE FROM YOUR MONADS WITH MTL,但要注意
对于其中任何一个,请注意 MonadTransformers 的缺点(不是 mtl-style/traits,请参阅第二部分):http://degoes.net/articles/effects-without-transformers