使用Monocle

时间:2017-12-13 06:12:56

标签: scala monocle-scala

我看到更新Map的{​​{3}},但我的语法有问题。

val pod: Lens[Event, Pod] = GenLens[Event](_.`object`)
val metadata: Lens[Pod, Metadata] = GenLens[Pod](_.metadata)
val labels: Lens[Metadata, Map[String, String]] = GenLens[Metadata](_.labels)

我想更新labels Map中的关键“应用”。但我无法得到以下内容进行编译:

(labels.composeOptional(index("app"))).set("whatever")(someLabels)

事实上,Monacle的一位作者的这个official example没有编译。

2 个答案:

答案 0 :(得分:3)

如果没有Event类的定义,我没有确切的答案,但是following the tutorial和大学示例,我能够在撰写本文时使用最新版本更新嵌套Map,monocle 1.5。 0-猫-M1。确保您的项目中同时具有单片核心和单片宏。然后,

import monocle.macros.GenLens
import monocle.function.At.at // // to get at Lens 
import monocle.std.map._      // to get Map instance for At

然后,按照大学的例子,

case class Lecturer(firstName: String, lastName: String, salary: Int)
case class Department(budget: Int, lecturers: List[Lecturer])
case class University(name: String, departments: Map[String, Department])

val departments = GenLens[University](_.departments) 

val uni = University("oxford", Map(
"Computer Science" -> Department(45, List(
  Lecturer("john"  , "doe", 10),
  Lecturer("robert", "johnson", 16)
)),
"History" -> Department(30, List(
  Lecturer("arnold", "stones", 20)
)))) 

我能够

(departments composeLens at("History")).set(Some(Department(30, List(Lecturer("arnold", "stones", 30)))))(uni)

与上面代码的主要区别在于使用at()并将Department包装为Some,以便在使用键从Map检索值进行访问时与Option返回类型相对应。

答案 1 :(得分:0)

考虑到someLabels的类型为Map[String, String],您的代码要么过多,要么仅为组合Optional提供错误的参数。如果我们在composeOptional中简化Lens[S, A]方法的签名,则会产生:

def composeOptional(other: Optional[A, B]): Optional[S, B]

Optional[A, B],在非常不精确的近似下,对应于允许的间接:

  • 查看A类型的值并获取其B类型的组件(如果缺少,则为A本身);
  • 通过替换A类型的组件来构建类型为B的新对象(如果没有这样的组件,则只返回原始对象)。

labels composeOptional index("app")会产生Optional[Metadata, String]。这显然不适用于Map[String, String]:它从MetadataMap[String, String](通过labels),然后立即从Map[String, String]String。 } element(通过index("app")),完全隐藏用户的地图访问权限。如果您只想在someLabels地图中的给定键设置值,则只需使用index

val someLabels1 = Map("app" -> "any")
val someLabels2 = Map("unit" -> "any")
index("app").set("whatever")(someLabels1) // Map("app" -> "whatever")
index("app").set("whatever")(someLabels2) // Map("unit" -> "any")

另一方面,您的撰写Optional适用于Metadata

case class Metadata(labels: Map[String, String])
val someLabels = Map("app" -> "any")
val meta = Metadata(someLabels)
(labels composeOptional index("app")).set("whatever")(meta) 
// Metadata(Map("app" -> "whatever")

我已使用以下版本(build.sbt)检查了它:

scalaVersion := 2.12.3

libraryDependencies ++= Seq(
  "com.github.julien-truffaut" %% "monocle-core" % "1.4.0",
  "com.github.julien-truffaut" %% "monocle-macro" % "1.4.0"
)