Scala:如何在Monocle中增加字段值
鉴于monocle项目中存在的问题,我想创建一个镜头,其中set调用将替换键/值对中的值,或者创建键/值对(如果它不存在) 然而,这似乎用索引(可以组成类型安全的)或at(不属于类型安全的)来表示Scala:如何在Monocle中增加字段值,scala,monocle-scala,Scala,Monocle Scala,鉴于monocle项目中存在的问题,我想创建一个镜头,其中set调用将替换键/值对中的值,或者创建键/值对(如果它不存在) 然而,这似乎用索引(可以组成类型安全的)或at(不属于类型安全的)来表示 //for replacing: (jsObject composeOptional index("age") composePrism jsNumber).set(45) //for creating: (jsObject composeLens at("age")).set(JsNumber(4
//for replacing:
(jsObject composeOptional index("age") composePrism jsNumber).set(45)
//for creating:
(jsObject composeLens at("age")).set(JsNumber(45)) <- will accept any old json
如果“nested”的键/值对还不存在,它将在nested处创建对象,然后添加字段
n(JsObject(Map.empty)) -> JsObject(Map("nested" -> JsObject("age" -> JsNumber(45)))
现在图书馆里有很多书 当您使用一些
Iso
或Prism
编写Optional
时,它会将右侧参数降级为POptional
,这就是问题所在
Iso[A,B]
和Prism[A,B]
不同于Lens[A,B]
和Optional[A,B]
的意义在于reverseGet
可以完全从B
创建A
的元素,而set
需要A
的原始值
因此,对于Optional
和Lens
而言,完全可以合法地修改部分值,而在原始Map
或JsObject
中没有此值,对于Iso
和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)
}
并报告它是否有帮助目前图书馆里有很多 当您使用一些
Iso
或Prism
编写Optional
时,它会将右侧参数降级为POptional
,这就是问题所在
Iso[A,B]
和Prism[A,B]
不同于Lens[A,B]
和Optional[A,B]
的意义在于reverseGet
可以完全从B
创建A
的元素,而set
需要A
的原始值
因此,对于Optional
和Lens
而言,完全可以合法地修改部分值,而在原始Map
或JsObject
中没有此值,对于Iso
和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)
}
并报告它是否有帮助让我们看看
索引
和处的JsObject的签名
:
def at(field: String): Lens[JsObject, Option[Json]]
def index(field: String): Optional[JsObject, Json]
at
是一个镜头
,因此其目标('Option[Json])始终存在。这意味着我们可以在JsonObject
的任何字段中添加
,删除
和更新
Json
元素
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 = {}
另一方面,索引
是一个可选的
,因此它是目标(Json
)可能存在也可能不存在。这意味着索引
只能更新
值,但不能添加
或删除
(jObjectPrism composeLens index("name")).set(jString("Robert"))(Json())
> res3: argonaut.Json = {}
(jObjectPrism composeLens index("name")).set(jString("Robert"))(res0)
> res4: argonaut.Json = {"name":"Robert"}
因此,回到您原来的问题,如果您想
在特定字段添加或更新值,您需要在处使用,并将Json
包装在部分(请参见res1
)中,它将覆盖或创建该字段中的Json
。让我们看看索引和处的签名JsObject
:
def at(field: String): Lens[JsObject, Option[Json]]
def index(field: String): Optional[JsObject, Json]
at
是一个镜头
,因此其目标('Option[Json])始终存在。这意味着我们可以在JsonObject
的任何字段中添加
,删除
和更新
Json
元素
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 = {}
另一方面,索引
是一个可选的
,因此它是目标(Json
)可能存在也可能不存在。这意味着索引
只能更新
值,但不能添加
或删除
(jObjectPrism composeLens index("name")).set(jString("Robert"))(Json())
> res3: argonaut.Json = {}
(jObjectPrism composeLens index("name")).set(jString("Robert"))(res0)
> res4: argonaut.Json = {"name":"Robert"}
因此,回到您原来的问题,如果您想在特定字段添加或更新值,您需要在处使用,并将Json
包装在部分(请参见res1
)中,它将覆盖或创建该字段中的Json
。如果您还提供jsObject
和jsNumber
和Index
实例的定义,那就太好了。问题似乎出在以可选类型实现compose…
。它通过modify
方法进行处理。如果原始值为None
我已经提出了一个问题,如果您还提供了jsObject
和jsNumber
和Index
实例的定义,那就太好了。问题似乎出在以可选类型实现compose…
。它通过modify
方法进行处理。如果原文是None
我已经提出了一个@JPullar,实际上我强烈建议接受朱利安·特鲁法特的答案。写下这个答案后,我已经阅读了朱利安的解释,并得出结论,我的方法是错误的。接受这个答案可能会导致对图书馆意识形态的误解。@JPullar实际上,我强烈建议接受朱利安·特鲁福的答案。在写下这个答案后,我已经阅读了Jullien在这里和讨论中的解释,并得出结论,我的方法是错误的。接受这个答案可能会导致对图书馆意识形态的误解。因此我最终使用at(也有在设置时删除字段的功能)(无).为了维护类型安全,我只使用了一个非组合棱柱.set(prism.reverseGet())所以我最终使用了at(还具有在设置(None)时删除字段的功能)。为了维护类型安全,我只使用了一个非组合棱柱.set(prism.reverseGet())来维护类型安全