Являются ли опции Monocle такими же, как частичные линзы?
Опции Monocle имеют следующие функции доступа (для Optional[C,A]
):
getOption: C => Option[A]
set: A => C => C
Это противоречит первоначальному определению (частичной) асимметричной линзы данных. Я бы ожидал:
getOption: C => Option[A]
setOption: A => C => Option[C]
В чем причина этого? Как получить классические частичные линзы с Monocle? При программировании линз я обнаружил, что гораздо сложнее обеспечить полную установку, чем получить...
1 ответ
Рассмотрим следующую частичную линзу для поиска значений в списке по индексу (обратите внимание, что это всего лишь педагогический пример, так как monocle.std.list.listIndex
предоставляет эту функциональность с полки):
import monocle.Optional
def listIndexOptional[A](i: Int): Optional[List[A], A] =
Optional[List[A], A](_.lift(i))(a => l =>
if (l.isDefinedAt(i)) l.updated(i, a) else l
)
Теперь мы можем определить Optional
который указывает на третий элемент в списке строк:
val thirdString = listIndexOptional[String](2)
И используйте это так:
scala> thirdString.set("0")(List("a", "b", "c"))
res4: List[String] = List(a, b, 0)
scala> thirdString.set("0")(List("a", "b"))
res5: List[String] = List(a, b)
Обратите внимание, что если третьего элемента нет, операция просто возвращает список без изменений. Если мы хотим узнать, был ли обновлен элемент, мы можем использовать setOption
:
scala> thirdString.setOption("0")(List("a", "b", "c"))
res6: Option[List[String]] = Some(List(a, b, 0))
scala> thirdString.setOption("0")(List("a", "b"))
res7: Option[List[String]] = None
Тот факт, что Optional.apply
метод принимает в качестве второго аргумента функцию A => S => S
отчасти это удобство, так как мы часто хотим определить частичные линзы таким образом, а частично, чтобы мы не могли определить частичную линзу, где getOption
а также setOption
не согласен с тем, существует ли цель.
Если вы действительно хотите, вы всегда можете определить Optional
с точки зрения A => S => Option[S]
сеттер, прикрепляя getOrElse(s)
в конце.