Scala:如何在Monocle中插入字段值

时间:2015-11-26 00:12:30

标签: scala monocle-scala

鉴于单片眼镜项目中的JsonExample,我想创建一个镜头,其中set set将替换键/值对中的值,或者如果它不存在则创建键/值对

然而,这似乎用索引(可以组成类型安全)或者at表示,它不是安全类型

//for replacing:
(jsObject composeOptional index("age") composePrism jsNumber).set(45)

//for creating:
(jsObject composeLens at("age")).set(JsNumber(45)) <- will accept any old json

我可以追求的是什么? 我也可以扩展它,如果年龄嵌套在另一个JsObject中,例如:

val n = (jsObject composeOptional index("nested") composePrism 
jsObject composeOptional index("age") composePrism jsNumber).set(45)

&#34;嵌套&#34;的键/值对还没有存在,它会在嵌套时创建对象,然后添加字段

n(JsObject(Map.empty)) -> JsObject(Map("nested" -> JsObject("age" -> JsNumber(45)))

2 个答案:

答案 0 :(得分:4)

让我们看一下index的{​​{1}}和at签名:

JsObject

def at(field: String): Lens[JsObject, Option[Json]] def index(field: String): Optional[JsObject, Json] at,因此其目标('Option [Json]')始终存在。这意味着我们可以在Lens的任意字段adddeleteupdate Json元素。

JsonObject

另一方面,import argonaut._, Argonaut._ import monocle.function._ (jObjectPrism composeLens at("name")).set(Some(jString("John")))(Json()) > res0: argonaut.Json = {"name":"John"} (jObjectPrism composeLens at("name")).set(Some(jString("Robert")))(res0) > res1: argonaut.Json = {"name":"Robert"} (jObjectPrism composeLens at("name")).set(None)(res0) > res2: argonaut.Json = {} index,因此目标(Optional)可能存在也可能不存在。这意味着Json只能index个值,但不能updateadd

delete

回到原来的问题,如果您想在特定字段中输入(jObjectPrism composeLens index("name")).set(jString("Robert"))(Json()) > res3: argonaut.Json = {} (jObjectPrism composeLens index("name")).set(jString("Robert"))(res0) > res4: argonaut.Json = {"name":"Robert"} add,则需要使用update并打包atJson(请参阅Some)中,它会在该字段覆盖或创建res1

答案 1 :(得分:3)

目前图书馆里有specific behaviour

当您使用OptionalIso撰写Prism时,它会将右侧参数降级为POptional而且这很麻烦。

Iso[A,B]Prism[A,B]Lens[A,B]Optional[A,B]的区别在于reverseGet可以完全从{{1}创建A的元素} B需要原始值set

因此,当AOptional完全合法时,您无法修改部分值,而在orignal LensMap中没有此值JsObjectIso您可以定义另一种行为。

在等待讨论the issue时,您可以使用以下解决方法

Prism

现在您可以尝试将代码更改为

implicit class POptStrictComposition[S, T, A, B](self: POptional[S, T, A, B]) {
  def sComposePrism[C, D](other: PPrism[A, B, C, D]) = new POptional[S, T, C, D] {
    def getOrModify(s: S): T \/ C =
      self.getOrModify(s).flatMap(a => other.getOrModify(a).bimap(self.set(_)(s), identity))

    def set(d: D): S => T =
      self.set(other.reverseGet(d))

    def getOption(s: S): Option[C] =
      self.getOption(s) flatMap other.getOption

    def modifyF[F[_] : Applicative](f: C => F[D])(s: S): F[T] =
      self.modifyF(other.modifyF(f))(s)

    def modify(f: C => D): S => T =
      self.modify(other.modify(f))
  }

  def ^!<-?[C, D](o: PPrism[A, B, C, D]) = sComposePrism(o)

  def sComposeIso[C, D](other: PIso[A, B, C, D]) = sComposePrism(other.asPrism)

  def ^!<->[C, D](o: PIso[A, B, C, D]) = sComposeIso(o)
}

并报告是否有帮助