Я впервые попробовал монокль.Как использовать монокль для изменения вложенной карты и другого поля в scala
Вот случай класс:
case class State(mem: Map[String, Int], pointer: Int)
И текущая модификация, с использованием стандартного Scala, что я хотел бы сделать:
def add1 = (s: State) => s.copy(
mem = s.mem.updated("a", s.mem("a") + 1),
pointer = s.pointer + 1
)
А вот моя реализация с моноклем
val mem = GenLens[State](_.mem)
val pointer = GenLens[State](_.pointer)
val add2 = (mem composeLens at("a")).modify(_.map(_ + 1)) andThen pointer.modify(_ + 1)
К сожалению, код не является чистым ...
- Есть ли более сжатый способ?
- Можем ли мы сгенерировать все шаблоны с помощью макросов?
[обновление] Я придумал комбинатор
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.
[Update2] Я очищенный код для комбинатора.
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)) }
}