I'd like to try Monocle library. But i could not find help resources for base syntax.
In short i need optics Map[K,V] -> A
having optics V -> A
, how could i define this?
Suppose i have some
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]
Next I encounter place where i need simple StateStore => StateStore
, so I'm importing
import monocle._
import monocle.std._
import monocle.syntax._
import monocle.function._
And trying to define first:
def setOpened(path: Path): StateStore => StateStore =
at(path) composeLens DirState.opened set true
Getting here
ambiguous implicit values: both method
atMap
intrait MapInstances
of type[K, V]=> monocle.function.At[Map[K,V],K,V]
and methodatSet
intrait SetInstances
of type[A]=> monocle.function.At[Set[A],A,Unit]
match expected typemonocle.function.At[S,Path,A]
Trying to change my definition to
def setOpened(path: Path): StateStore => StateStore =
index(path) composeLens DirState.opened set true
Getting now:
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
, buttrait Index
is invariant in typeA
. You may wish to defineA
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)
let's have a look at the type of 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]
}
So index
summon an instance of type class Index
of type Index[S, I, A]
.
This permits to use index
for Map
, List
, Vector
and so on.
The problem is that scala compiler needs to infer 3 types: S
, I
and A
at the call site of index
. I
is easy, it is the type of the parameter you pass to index
. However,S
and A
are only know when you call set
.
The apply
syntax has been created to guide type inference for such scenario, basically applyOptional
captures S
which is Map[Path, DirState]
. This gives enough information for the compiler to infer A =:= DirState
.