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

Я хочу попробовать библиотеку 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)


person Odomontois    schedule 10.08.2015    source источник


Ответы (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 вызывает экземпляр типа class Index типа Index[S, I, A]. Это позволяет использовать index для Map, List, Vector и так далее.

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

Синтаксис apply был создан для управления выводом типа для такого сценария, в основном applyOptionalcaptures S, который равен Map[Path, DirState]. Это дает компилятору достаточно информации, чтобы вывести A =:= DirState.

person Julien Truffaut    schedule 10.08.2015

В репозитории 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

person Armin    schedule 13.01.2017