1

我有一个使用默认值创建的嵌套案例类的结构:

case class Alpha(text: String = "content")
case class Beta(alpha: Alpha = Alpha())
case class Gamma(beta: Option[Beta] = None)

我想用默认值创建整个东西,然后使用 Monocle 特别修改需要非默认的元素。

用iso很容易。我可以使用组合指定导航,然后使用 set 修改内部元素:

object Beta {
  val alphaI: Iso[Beta, Alpha] = GenIso[Beta, Alpha]
}
object Alpha {
  val textI: Iso[Alpha, String] = GenIso[Alpha, String]
}

(Beta.alphaI composeIso Alpha.textI).set("foo")(Beta()) shouldBe Beta(Alpha("foo"))

不幸的是,使用 prims 似乎并不那么优雅,因为set/modify只会在导航期间定义了所有选项时修改内部元素(Some(...)

object Gamma {
  val betaI: Iso[Gamma, Option[Beta]] = GenIso[Gamma, Option[Beta]]
  val betaP: Prism[Gamma, Beta] = Prism[Gamma, Beta](_.beta)(a => Gamma(Some(a)))
}

val navigateToText: Prism[Gamma, String] = Gamma.betaP composeIso Beta.alphaI composeIso Alpha.textI

navigateToText.set("foo")(Gamma(None)) shouldBe Gamma(None)
navigateToText.set("foo")(Gamma(Some(Beta()))) shouldBe Gamma(Some(Beta(Alpha("foo"))))

到目前为止,我想出的最好的方法是使用组合光学设置Some()路径的每个可选元素,然后一直使用组合光学设置我们感兴趣的元素。

(Gamma.betaI.set(Some(Beta())) andThen navigateToText.set("foo")) (Gamma()) shouldBe Gamma(Some(Beta(Alpha("foo"))))

理想情况下,我希望组合的每个构建块都将可选值设置为Some(defaultValue)如果它们最初是None. 显然,需要定义构建块,包括路径步骤的适当默认值。有什么建议么?

包含导入的完整代码:https ://github.com/jcaraballo/navigating-fixtures-with-monocle/blob/master/src/test/scala/pr/NavigateIntoOptionSpec.scala

4

1 回答 1

2

您可以使用belowfromPrism诸如光学组合中的类型匹配:

import monocle.macros.GenIso
import scalaz.std.option._
case class Alpha(text: String = "content")
case class Beta(alpha: Alpha = Alpha())
case class Gamma(beta: Option[Beta] = None)

val navigateToText = GenIso[Gamma, Option[Beta]] composePrism
  GenIso[Beta, Alpha].asPrism.below[Option] composePrism
  GenIso[Alpha, String].asPrism.below[Option]

navigateToText.set(Some("foo"))(Gamma(None))                     // Gamma(Some(Beta(Alpha(foo))))
navigateToText.set(Some("foo"))(Gamma(Some(Beta(Alpha("bar"))))) // Gamma(Some(Beta(Alpha(foo))))
于 2017-03-08T10:17:05.723 回答