You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
3.6 KiB
127 lines
3.6 KiB
package green.thisfieldwas.embracingnondeterminism.data
|
|
|
|
/** The `Option` class encodes a dimension contextualized by the presence or
|
|
* absence of an instance of the term `A`. The presence of `A` is unknown at
|
|
* runtime without specific knowledge of the inputs to the operation producing
|
|
* the context.
|
|
*
|
|
* This context is in the desired case if an instance of `A` is present. The
|
|
* absence of `A` is the undesired case.
|
|
*
|
|
* This context may be regarded as a "null done right", as it strongly-types
|
|
* the notion of absence and requires that the absent case be handled.
|
|
*
|
|
* @tparam A
|
|
* The type of the instance contained.
|
|
*/
|
|
sealed trait Option[+A] {
|
|
|
|
/** Gets the instance of term `A` if it exists.
|
|
*
|
|
* @return
|
|
* The instance of `A`.
|
|
* @throws NoSuchElementException
|
|
* if the instance of `A` is absent.
|
|
*/
|
|
def get: A
|
|
|
|
/** Gets whether the instance of `A` is present.
|
|
*
|
|
* @return
|
|
* True if present.
|
|
*/
|
|
def isSome: Boolean = !isNone
|
|
|
|
/** Gets whether the instance of `A` is absent.
|
|
*
|
|
* @return
|
|
* True if absent.
|
|
*/
|
|
def isNone: Boolean = this == None
|
|
}
|
|
|
|
/** Encodes the present case of an instance of term `A`. That is to say, there
|
|
* is "Some" `A` here.
|
|
*
|
|
* @param get
|
|
* The instance of term `A`.
|
|
* @tparam A
|
|
* The type of the instance contained.
|
|
*/
|
|
case class Some[+A](get: A) extends Option[A]
|
|
|
|
/** Encodes the absent ccase of an instance of term `A`. That is, if you were to
|
|
* inspect for some instance of term `A`, you would see "None" here.
|
|
*/
|
|
case object None extends Option[Nothing] {
|
|
|
|
override def get: Nothing = throw new NoSuchElementException("None.get")
|
|
}
|
|
|
|
object Option {
|
|
|
|
/** A smart constructor for a "Some" typed specifically as an `Option`.
|
|
*
|
|
* @param a
|
|
* The present instance of term `A`.
|
|
* @tparam A
|
|
* The type of the instance contained.
|
|
* @return
|
|
* An `Option` in the desired case with a present instance of term `A`.
|
|
*/
|
|
def apply[A](a: A): Option[A] = Some(a)
|
|
|
|
/** A smart constructor for a "None" typed specifically as an `Option`.
|
|
*
|
|
* @tparam A
|
|
* The type of the instance contained.
|
|
* @return
|
|
* An `Option` in the undesired case with an absent instance of term `A`.
|
|
*/
|
|
def apply[A](): Option[A] = None
|
|
|
|
/** Allows for idiomatic pattern matching syntax:
|
|
*
|
|
* {{{
|
|
* option match {
|
|
* case Some(x) => ???
|
|
* case None => ???
|
|
* }
|
|
* }}}
|
|
*
|
|
* @param o
|
|
* The option to unapply.
|
|
* @tparam A
|
|
* The type of the instance contained.
|
|
* @return
|
|
* A Scala `Option` corresponding to this `Option`.
|
|
*/
|
|
def unapply[A](o: Option[A]): scala.Option[A] = o match {
|
|
case Some(a) => scala.Some(a)
|
|
case None => scala.None
|
|
}
|
|
|
|
implicit val optionFunctor: Functor[Option] = new Functor[Option] {
|
|
|
|
/** Given a structure `F[A]` and function `f: A => B`, if the structure is
|
|
* in the desired case, then apply the function such that `F[A] => F[B]`.
|
|
* If the structure `F[A]` is in the undesired case, then propagate the
|
|
* undesired case as `F[B]`.
|
|
*
|
|
* @param fa
|
|
* The instance of the structure to apply the function to.
|
|
* @param f
|
|
* The function to apply, if the structure is in the desired case.
|
|
* @tparam A
|
|
* The type of instances contained within the structure.
|
|
* @tparam B
|
|
* The type to map the instances into.
|
|
* @return
|
|
* The resulting structure.
|
|
*/
|
|
override def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa match {
|
|
case Some(a) => Some(f(a))
|
|
case None => None
|
|
}
|
|
}
|
|
}
|
|
|