2017-02-22 4 views
0

У меня есть структура вложенных классов дела, которые я создаю со значениями по умолчанию:Определение дополнительных значений в пути, построенный с сложенной оптикой

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

Я хотел бы создать все эту со значениями по умолчанию, а затем модифицировать элементы, в частности, которые должны быть недействительными с использованием Monocle.

С isos легко. Я могу указать навигации с составом, а затем использовать набор для изменения внутреннего элемента:

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")) 

К сожалению, с примы не кажется, что элегантный, как и 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() каждый дополнительный элемент пути, а затем Сформированное Optic весь путь вниз для того, чтобы задать элемент, который мы интересовали, для начала ,

(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

ответ

1

Вы можете использовать below из Prism, таких как спичка типов в составе оптики:

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)))) 
+0

Отлично, что работает очень хорошо! И он также работает с объективами, когда у родителя с дополнительным ребенком есть другие дети. (Я не могу заставить SO правильно форматировать код здесь, но я пробовал композицию с объективом в https://github.com/jcaraballo/navigating-fixtures-with-monocle/blob/master/src/test /scala/pr/NavigateIntoOptionSpec.scala) – qtwo

Смежные вопросы