Монада состояния Scala (scalaz) — сопоставление с типом состояния Option

Как я могу применить следующую функцию?

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?


person ak.    schedule 25.12.2015    source источник


Ответы (1)


Одним из способов создания функции wrapIntoOption будет вызов run для переданного State[S, A] и преобразование полученного кортежа (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)
person Peter Neyens    schedule 28.12.2015