如何使用单片眼镜更新地图

How to update Map using monocle

我想试试 Monocle 图书馆。 但是我找不到基本语法的帮助资源。

简而言之,我需要光学器件 Map[K,V] -> A 具有光学器件 V -> A,我该如何定义它?

假设我有一些

import monocle.macros.GenLens

case class DirState(opened: Boolean)

object DirState {
  val opened = GenLens[DirState](_.opened)
}

type Path = List[String]
type StateStore = Map[Path, DirState]

接下来我遇到需要简单的地方StateStore => StateStore,所以我正在导入

import monocle._
import monocle.std._
import monocle.syntax._
import monocle.function._

并首先尝试定义:

def setOpened(path: Path): StateStore => StateStore = 
  at(path) composeLens DirState.opened set true

到达此处

ambiguous implicit values: both method atMap in trait MapInstances of type [K, V]=> monocle.function.At[Map[K,V],K,V] and method atSet in trait SetInstances of type [A]=> monocle.function.At[Set[A],A,Unit] match expected type monocle.function.At[S,Path,A]

试图将我的定义更改为

def setOpened(path: Path): StateStore => StateStore =
  index(path) composeLens DirState.opened set true

现在开始:

type mismatch; found : monocle.function.Index[Map[Path,Nothing],Path,Nothing] (which expands to) monocle.function.Index[Map[List[String],Nothing],List[String],Nothing] required: monocle.function.Index[Map[Path,Nothing],Path,A] (which expands to) monocle.function.Index[Map[List[String],Nothing],List[String],A]

Note: Nothing <: A, but trait Index is invariant in type A. You may wish to define A as +A instead. (SLS 4.5)

import monocle.function.index._
import monocle.std.map._
import monocle.syntax._

def setOpened(path: Path)(s: StateStore): StateStore =
  (s applyOptional index(path) composeLens DirState.opened).set(true)

我们来看看index

的类型
def index[S, I, A](i: I)(implicit ev: Index[S, I, A]): Optional[S, A] = 
  ev.index(i)

trait Index[S, I, A] {
  def index(i: I): Optional[S, A]
}

所以index召唤一个类型classIndex类型Index[S, I, A]的实例。 这允许对 MapListVector 等使用 index

问题是 scala 编译器需要在 index 的调用位置推断出 3 种类型:SIAI很简单,就是你传给index的参数类型。但是,SA 只有在调用 set 时才知道。

已创建 apply 语法来指导此类场景的类型推断,基本上 applyOptional 捕获 SMap[Path, DirState]。这为编译器提供了足够的信息来推断 A =:= DirState.

Monocle 存储库中提供了很多如何执行此操作的示例以及许多其他方便的技巧:

https://github.com/julien-truffaut/Monocle/blob/master/example/src/test/scala/monocle/function/

更具体地针对此场景: https://github.com/julien-truffaut/Monocle/blob/master/example/src/test/scala/monocle/function/FilterIndexExample.scala