Scala (scalaz) State monad - 映射到 Option 状态类型

Posted

技术标签:

【中文标题】Scala (scalaz) State monad - 映射到 Option 状态类型【英文标题】:Scala (scalaz) State monad - map over Option state type 【发布时间】:2016-03-31 10:23:02 【问题描述】:

如何申请实现以下功能?

def wrapIntoOption(state: State[S, A]): State[Option[S], Option[A]]

大局是这样的:

case class Engine(cylinders: Int)
case class Car(engineOpt: Option[Engine])

val engineOptLens = Lens.lensu((c, e) => c.copy(engineOpt = e), _.engineOpt)

def setEngineCylinders(count: Int): State[Engine, Int] = State  engine =>
  (engine.copy(cylinders = count), engine.cylinders)


def setEngineOptCylinders(count: Int): State[Option[Engine], Option[Int]] = 
  ??? // how to reuse setEngineCylinders?


def setCarCylinders(count: Int): State[Car, Option[Int]] = 
  engineOptLens.lifts(setEngineOptCylinders)

有没有更好的方法来处理 Option 属性?

【问题讨论】:

【参考方案1】:

创建wrapIntoOption 函数的一种方法是在传递的State[S, A] 上调用run,并将生成的(S, A) 元组转换为(Option[S], Option[A])

import scalaz.State
import scalaz.std.option._
import scalaz.syntax.std.option._

def wrapIntoOption[S, A](state: State[S, A]): State[Option[S], Option[A]] =
  State(_.fold((none[S], none[A])) oldState =>
    val (newState, result) = state.run(oldState)
    (newState.some, result.some)
  )

然后您可以将setEngineOptCylinders 定义为:

def setEngineOptCylinders(count: Int): State[Option[Engine], Option[Int]] = 
  wrapIntoOption(setEngineCylinders(count))

你可以用作:

scala> val (newEngine, oldCylinders) = setEngineOptCylinders(8).run(Engine(6).some)
newEngine: Option[Engine] = Some(Engine(8))
oldCylinders: Option[Int] = Some(6)

【讨论】:

以上是关于Scala (scalaz) State monad - 映射到 Option 状态类型的主要内容,如果未能解决你的问题,请参考以下文章

为啥 IvyDE 可以使用 scala-library 的源而不使用 scalaz-core_2.10.0-RC3-7.0.0-M5 的源?

Scalaz(32)- Free :lift - Monad生产线

Scalaz(44)- concurrency :scalaz Future,尚不完整的多线程类型

Cats- 从Free开始,Free cats

Functor组合的例子

mona!mona!mona!