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

时间:2015-08-10 12:46:48

标签: scala lenses monocle-scala

我想尝试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

到这里

  

含糊不清的隐含值:atMap中的方法trait MapInstances   输入[K, V]=> monocle.function.At[Map[K,V],K,V]和方法atSet   类型为trait SetInstances的{​​{1}}   匹配预期类型   [A]=> monocle.function.At[Set[A],A,Unit]

尝试将我的定义更改为

monocle.function.At[S,Path,A]

立即行动:

  

类型不匹配;发现:   def setOpened(path: Path): StateStore => StateStore = index(path) composeLens DirState.opened set true       (扩展为)monocle.function.Index[Map[Path,Nothing],Path,Nothing]   需要:   monocle.function.Index[Map[List[String],Nothing],List[String],Nothing]       (扩展为)monocle.function.Index[Map[Path,Nothing],Path,A]

     

注意:   monocle.function.Index[Map[List[String],Nothing],List[String],A],但Nothing <: Atrait Index类型中不变。你可能希望   将A定义为A。 (SLS 4.5)

2 个答案:

答案 0 :(得分:8)

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召唤类型为Index的类型Index[S, I, A]的实例。 这允许index使用MapListVector等等。

问题是scala编译器需要在S的调用站点推断出3种类型:IAindexI很简单,它是您传递给index的参数的类型。但是,SA仅在您致电set时知道。

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

答案 1 :(得分:0)