Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are Monocle's Optionals the same as partial Lenses?

Monocle's optionals have the following access functions (for Optional[C,A]):

getOption: C => Option[A]
set: A => C => C

This is at odds with the original definition of (partial) asymmetric data lenses. I would expect:

getOption: C => Option[A]
setOption: A => C => Option[C]

What is the reason for that? How do I obtain classic partial lenses with Monocle? When programming lenses I found that it much more problematic to ensure totality of set than of get ...

like image 956
Andrzej Wąsowski Avatar asked Mar 14 '23 04:03

Andrzej Wąsowski


1 Answers

Consider the following partial lens for looking up values in a list by index (note that this is just a pedagogical example, since monocle.std.list.listIndex provides this functionality off the shelf):

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
  )

Now we can define an Optional that points to the third item in a list of strings:

val thirdString = listIndexOptional[String](2)

And use it like this:

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)

Note that if there is no third item, the operation just returns the list unmodified. If we wanted to know whether the item had been updated, we can use 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

The fact that the Optional.apply method takes as its second argument a function A => S => S is partly a convenience, since we often want to define partial lenses in this way, and partly so that we can't define a partial lens where getOption and setOption disagree on whether the target exists.

If you really want to, you can always define an Optional in terms of a A => S => Option[S] setter by tacking a getOrElse(s) on the end.

like image 78
Travis Brown Avatar answered Mar 23 '23 04:03

Travis Brown