在使用复合光学器件构建的路径中定义可选值
Defining optional values in a path built with composed optics
我有一个用默认值创建的嵌套大小写结构 类:
case class Alpha(text: String = "content")
case class Beta(alpha: Alpha = Alpha())
case class Gamma(beta: Option[Beta] = None)
我想使用默认值创建整个事物,然后使用 Monocle 修改特别需要非默认值的元素。
使用 isos 很容易。我可以用composition指定navigation,然后用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
。显然,需要定义构建块,包括路径步骤的适当默认值。
有什么建议吗?
您可以使用 Prism
中的 below
例如光学成分中的类型匹配:
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))))
我有一个用默认值创建的嵌套大小写结构 类:
case class Alpha(text: String = "content")
case class Beta(alpha: Alpha = Alpha())
case class Gamma(beta: Option[Beta] = None)
我想使用默认值创建整个事物,然后使用 Monocle 修改特别需要非默认值的元素。
使用 isos 很容易。我可以用composition指定navigation,然后用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
。显然,需要定义构建块,包括路径步骤的适当默认值。
有什么建议吗?
您可以使用 Prism
中的 below
例如光学成分中的类型匹配:
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))))