如何使用单片眼镜修改Scala中的嵌套地图和另一个字段 [英] How to use monocle to modify a nested map and another field in scala

查看:117
本文介绍了如何使用单片眼镜修改Scala中的嵌套地图和另一个字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是第一次尝试单片眼镜.

I'm giving a try to monocle for the first time.

这里是案例类:

case class State(mem: Map[String, Int], pointer: Int)

我想使用标准scala进行的当前修改:

And the current modification, using standard scala, that I would like to do :

def add1 = (s: State) => s.copy(
  mem = s.mem.updated("a", s.mem("a") + 1),
  pointer = s.pointer + 1
)

这是我对单片眼镜的实现

And here is my implementation with monocle

val mem = GenLens[State](_.mem)
val pointer = GenLens[State](_.pointer)
val add2 = (mem composeLens at("a")).modify(_.map(_ + 1)) andThen pointer.modify(_ + 1)

不幸的是,代码并不干净……

Unfortunately, the code is not cleaner…

  1. 还有更简洁的方法吗?
  2. 我们可以用宏生成所有样板吗?

[更新]我想出了一个组合器

[update] I've come up with a combinator

  def combine[S, A, B](lsa : Lens[S, A], f: A => A, lsb: Lens[S, B], g: B => B) : S => S = { s =>
    val a = lsa.get(s)
    val b = lsb.get(s)
    val s2 = lsa.set(f(a))
    val s3 = lsb.set(g(b))
    s2(s3(s))
  }

问题是我仍然需要生成一个中间的无用的S.

The problem is that I still need to produce an intermediary and useless S.

[update2]我已经清理了组合器的代码.

[update2] I've cleaned up the code for the combinator.

  def mergeLens[S, A, B](lsa : Lens[S, A], lsb : Lens[S, B]) : Lens[S, (A, B)] =
    Lens.apply[S, (A, B)](s => (lsa.get(s), lsb.get(s)))(t => (lsa.set(t._1) andThen lsb.set(t._2)))

  def combine[S, A, B](lsa : Lens[S, A], f: A => A, lsb: Lens[S, B], g: B => B) : S => S = {
    mergeLens(lsa, lsb).modify { case (a, b) => (f(a), g(b)) }
  }

推荐答案

您可以使用index而不是at来获得一个略短的版本:

You can get a slightly shorter version using index instead of at:

(mem composeOptional index("a")).modify(_ + 1) andThen pointer.modify(_ + 1)

但是,如果两个Lenses指向同一字段,则mergeLens也称为水平构图不满足Lens律:

However, mergeLens also known as horizontal composition does not satisfy the Lens law if the two Lenses point to the same field:

  import monocle.macros.GenLens

  case class Person(name: String, age: Int)
  val age = GenLens[Person](_.age)

  val age2 = mergeLens(age, age)
  val john = Person("John", 25)
  age2.get(age2.set((5, 10))(john)) != (5, 10)

这篇关于如何使用单片眼镜修改Scala中的嵌套地图和另一个字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆