Как обновить карту с помощью монокля

Я хотел бы попробовать библиотеку 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 типа [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 <: A, но trait Index инвариантен по типу A, Вы можете определить A как +A вместо. (SLS 4.5)

2 ответа

Решение
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 за Map, List, Vector и так далее.

Проблема в том, что компилятору scala нужно определить 3 типа: S, I а также A на сайте вызова index, I это просто, это тип параметра, который вы передаете index, Тем не мение,S а также A знают только когда ты звонишь set,

apply Синтаксис был создан, чтобы вести вывод типа для такого сценария, в основном applyOptionalзахваты S который Map[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

Другие вопросы по тегам