## Optional

#### Optional

An `Optional` is an Optic used to zoom inside a `Product`, e.g. `case class`, `Tuple`, `HList` or even Map. Unlike the `Lens`, the element that the `Optional` focuses on may not exist.

`Optionals` have two type parameters generally called `S` and `A`: `Optional[S, A]` where `S` represents the `Product` and `A` an optional element inside of `S`.

Let’s take a simple list with integers.

We can create an `Optional[List[Int], Int]` which zooms from a `List[Int]` to its potential head by supplying a pair of functions:

• `getOption: List[Int] => Option[Int]`
• `set: Int => List[Int] => List[Int]`
``````import monocle.Optional

val head = Optional[List[Int], Int] {
case Nil => None
case x :: xs => Some(x)
} { a =>
{
case Nil => Nil
case x :: xs => a :: xs
}
}``````

Once we have an `Optional`, we can use the supplied `nonEmpty` function to know if it matches:

``````val xs = List(1, 2, 3)
val ys = List.empty[Int]``````
``````head.nonEmpty(xs) should be(res0)

We can use the supplied `getOrModify` function to retrieve the target if it matches, or the original value:

``````head.getOrModify(xs)
// res2: Either[List[Int],Int] = Right(1)

// res3: Either[List[Int],Int] = Left(List())``````

The function `getOrModify` is mostly used for polymorphic optics. If you use monomorphic optics, use function `getOption`

We can use the supplied `getOption` and set functions:

``````head.getOption(xs) should be(res0)

We can also modify the target of `Optional` with a function:

``````head.modify(_ + 1)(xs) should be(res0)

Or use `modifyOption` / `setOption` to know if the update was successful:

``````head.modifyOption(_ + 1)(xs) should be(res0)

#### Laws

An `Optional` must satisfy all properties defined in `OptionalLaws` in core module. You can check the validity of your own `Optional` using `OptionalTests` in law module.

`getOptionSet` states that if you `getOrModify` a value `A` from `S` and then `set` it back in, the result is an object identical to the original one.

`setGetOption` states that if you `set` a value, you always `getOption` the same value back.

``````val head = Optional[List[Int], Int] {
case Nil => None
case x :: xs => Some(x)
} { a =>
{
case Nil => Nil
case x :: xs => a :: xs
}
}
class OptionalLaws[S, A](optional: Optional[S, A]) {

def getOptionSet(s: S): Boolean =
optional.getOrModify(s).fold(identity, optional.set(_)(s)) == s

def setGetOption(s: S, a: A): Boolean =
optional.getOption(optional.set(a)(s)) == optional.getOption(s).map(_ => a)

}
new OptionalLaws(head).getOptionSet(List(1, 2, 3)) should be(res0)

new OptionalLaws(head).setGetOption(List(1, 2, 3), 20) should be(res1)``````