alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (Maybe.scala)

This example Scala source code file (Maybe.scala) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Scala by Example" TM.

Learn more about this Scala project at its project page.

Java - Scala tags/keywords

boolean, empty, firstmaybe, just, lastmaybe, maybe, minmaybe, monoid, option, order, show, tag

The Maybe.scala Scala example source code

package scalaz

import scala.util.control.NonFatal
import scala.reflect.ClassTag
import Ordering._
import Isomorphism.{<~>, IsoFunctorTemplate}

/** An optional value
 *
 * A `Maybe[A]` will either be a wrapped `A` instance (`Just[A]`), or a lack of underlying
 * `A` instance (`Empty[A]`).
 *
 * `Maybe[A]` is isomorphic to `Option[A]`, however there are some differences between
 * the two. `Maybe` is invariant in `A` while `Option` is covariant. `Maybe[A]` does not expose
 * an unsafe `get` operation to access the underlying `A` value (that may not exist) like
 * `Option[A]` does. `Maybe[A]` does not come with an implicit conversion to `Iterable[A]` (a
 * trait with over a dozen super types).
 */
sealed abstract class Maybe[A] {
  import Maybe._

  /** Catamorphism.
   * Run the given function on the underlying value if present, otherwise return
   * the provided fallback value */
  final def cata[B](f: A => B, b: => B): B =
    this match {
      case Just(a) => f(a)
      case Empty() => b
    }

  /** Return the underlying value if present, otherwise the provided fallback value */
  final def getOrElse(a: => A): A =
    cata(identity, a)

  /** alias for [[getOrElse]] */
  final def |(a: => A): A =
    getOrElse(a)

  /** Turn the underlying value into a failure validation if present, otherwise
   * return a success validation with the provided fallback value */
  final def toFailure[B](b: => B): Validation[A, B] =
    cata(Validation.failure, Success(b))

  /** Turn the underlying value into a success validation if present, otherwise
   * return a failure validation with the provided fallback value */
  final def toSuccess[B](b: => B): Validation[B, A] =
    cata(Validation.success, Failure(b))

  /** Turn the underlying value into a left disjunction if present, otherwise
   * return a right disjunction with the provided fallback value */
  final def toLeft[B](b: => B): A \/ B =
    cata(\/.left, \/-(b))

  /** alias for [[toLeft]] */
  final def <\/[B](b: => B): A \/ B =
    toLeft(b)

  /** Turn the underlying value into a right disjunction if present, otherwise
   * return a left disjunction with the provided fallback value */
  final def toRight[B](b: => B): B \/ A =
    cata(\/.right, -\/(b))

  /** alias for [[toRight]] */
  final def \/>[B](b: => B): B \/ A =
    toRight(b)

  /** True if an underlying value is present */
  final def isJust: Boolean =
    cata(_ => true, false)

  /** True if no underlying value is present */
  final def isEmpty: Boolean =
    cata(_ => false, true)

  final def map[B](f: A => B): Maybe[B] =
    cata(f andThen just[B], empty[B])

  final def flatMap[B](f: A => Maybe[B]) =
    cata(f, empty[B])

  /** Convert to a standard library `Option` */
  final def toOption: Option[A] =
    cata(Some(_), None)

  /** Return this instance if it is a [[Maybe.Just]], otherwise the provided fallback */
  final def orElse(oa: => Maybe[A]): Maybe[A] =
    cata(_ => this, oa)

  /** Tag with [[Tags.First]] */
  final def first: FirstMaybe[A] = Tag(this)

  /** Tag with [[Tags.Last]] */
  final def last: LastMaybe[A] = Tag(this)

  /** Tag with [[Tags.Min]] */
  final def min: MinMaybe[A] = Tag(this)

  /** Tag with [[Tags.Max]] */
  final def max: MaxMaybe[A] = Tag(this)

  final def cojoin: Maybe[Maybe[A]] = map(just)

  final def cobind[B](f: Maybe[A] => B): Maybe[B] =
    map(_ => f(this))

  final def zip[B](fb: Maybe[B]): Maybe[(A, B)] =
    for {
      a <- this
      b <- fb
    } yield (a, b)

  final def zipWith[B, C](fb: Maybe[B])(f: (A, B) => C): Maybe[C] =
    for {
      a <- this
      b <- fb
    } yield f(a, b)

  final def filter(f: A => Boolean): Maybe[A] =
    flatMap(a => if (f(a)) this else empty)

  final def filterNot(f: A => Boolean): Maybe[A] =
    filter(f.andThen(!_))

  /** Return `true` if this is a [[Maybe.Empty]] or if this is a [[Maybe.Just]]
   * and the underlying value satisfies the provided predicate */
  final def forall(f: A => Boolean): Boolean =
    cata(f, true)

  /** Return `true` if this is a [[Maybe.Just]] and the underlying value
   * satisfies the provided predicate */
  final def exists(f: A => Boolean): Boolean =
    cata(f, false)

  /** Return the underlying value if present, otherwise the monoid zero */
  final def orZero(implicit F: Monoid[A]): A =
    getOrElse(F.zero)

  /** alias for [[orZero]] */
  final def unary_~(implicit z: Monoid[A]): A =
    orZero

  /**
   * Return the underlying value wrapped in type `F` if present, otherwise the
   * empty value for type `F` */
  final def orEmpty[F[_]](implicit F: Applicative[F], G: PlusEmpty[F]): F[A] =
    cata(F.point(_), G.empty)
}

object Maybe extends MaybeInstances {

  final case class Empty[A]() extends Maybe[A]

  final case class Just[A](a: A) extends Maybe[A]

  val optionMaybeIso: Option <~> Maybe =
    new IsoFunctorTemplate[Option, Maybe] {
      def to[A](fa: Option[A]) = std.option.toMaybe(fa)
      def from[A](ga: Maybe[A]) = ga.toOption
    }

  /** Wrap a value in Just, or return Empty if the value is null */
  final def fromNullable[A](a: A): Maybe[A] =
    if (null == a) empty else just(a)

  final def empty[A]: Maybe[A] = Empty()

  final def just[A](a: A): Maybe[A] = Just(a)

  final def fromOption[A](oa: Option[A]): Maybe[A] =
    std.option.cata(oa)(just, empty)

  def fromTryCatchThrowable[T, E <: Throwable](a: => T)(implicit nn: NotNothing[E], ex: ClassTag[E]): Maybe[T] = try {
    just(a)
  } catch {
    case e if ex.runtimeClass.isInstance(e) => empty
  }

  def fromTryCatchNonFatal[T](a: => T): Maybe[T] = try {
    just(a)
  } catch {
    case NonFatal(t) => empty
  }
}

sealed abstract class MaybeInstances {
  import Maybe._

  implicit def maybeEqual[A : Equal]: Equal[Maybe[A]] = new MaybeEqual[A] {
    def A = implicitly
  }

  implicit def maybeOrder[A : Order]: Order[Maybe[A]] = new Order[Maybe[A]] with MaybeEqual[A] {
    def A = implicitly

    def order(fa1: Maybe[A], fa2: Maybe[A]) =
      fa1.cata(
        a1 => fa2.cata(
          a2 => Order[A].order(a1, a2),
          GT),
        fa2.cata(_ => LT, EQ))
  }

  implicit def maybeShow[A](implicit A: Show[A]): Show[Maybe[A]] =
    Show.show(_.cata(
      a => Cord("Just(", A.show(a), ")"),
      "Empty"))

  implicit def maybeMonoid[A](implicit A: Semigroup[A]): Monoid[Maybe[A]] = new Monoid[Maybe[A]] {
    def append(fa1: Maybe[A], fa2: => Maybe[A]) =
      fa1.cata(
        a1 => fa2.cata(a2 => just(A.append(a1, a2)), fa1),
        fa2.cata(_ => fa2, empty))

    def zero = empty
  }

  implicit def maybeFirstMonoid[A]: Monoid[FirstMaybe[A]] = new Monoid[FirstMaybe[A]] {
    val zero: FirstMaybe[A] = Tag(empty)

    def append(fa1: FirstMaybe[A], fa2: => FirstMaybe[A]): FirstMaybe[A] = Tag(Tag.unwrap(fa1).orElse(Tag.unwrap(fa2)))
  }

  implicit def maybeFirstShow[A](implicit A: Show[Maybe[A]]): Show[FirstMaybe[A]] = Tag.subst(A)

  implicit def maybeFirstOrder[A](implicit A: Order[Maybe[A]]): Order[FirstMaybe[A]] = Tag.subst(A)

  implicit def maybeFirstMonad: Monad[FirstMaybe] = Tags.First.subst1[Monad, Maybe](Monad[Maybe])

  implicit def maybeLastMonoid[A]: Monoid[LastMaybe[A]] = new Monoid[LastMaybe[A]] {
    val zero: LastMaybe[A] = Tag(empty)

    def append(fa1: LastMaybe[A], fa2: => LastMaybe[A]): LastMaybe[A] = Tag(Tag.unwrap(fa2).orElse(Tag.unwrap(fa1)))
  }

  implicit def maybeLastShow[A](implicit A: Show[Maybe[A]]): Show[LastMaybe[A]] = Tag.subst(A)

  implicit def maybeLastOrder[A](implicit A: Order[Maybe[A]]): Order[LastMaybe[A]] = Tag.subst(A)

  implicit def maybeLastMonad: Monad[LastMaybe] = Tags.Last.subst1[Monad, Maybe](Monad[Maybe])

  implicit def maybeMin[A](implicit o: Order[A]) = new Monoid[MinMaybe[A]] {
    def zero: MinMaybe[A] = Tag(empty)

    def append(f1: MinMaybe[A], f2: => MinMaybe[A]) = Tag( (Tag unwrap f1, Tag unwrap f2) match {
      case (Just(v1), Just(v2)) => Just(Order[A].min(v1, v2))
      case (_f1 @ Just(_), Empty()) => _f1
      case (Empty(), _f2 @ Just(_)) => _f2
      case (Empty(), Empty()) => empty
    })
  }

  implicit def maybeMinShow[A: Show]: Show[MinMaybe[A]] = Tag.subst(Show[Maybe[A]])

  implicit def maybeMinOrder[A: Order]: Order[MinMaybe[A]] = Tag.subst(Order[Maybe[A]])

  implicit def maybeMinMonad: Monad[MinMaybe] = Tags.Min.subst1[Monad, Maybe](Monad[Maybe])

  implicit def maybeMax[A](implicit o: Order[A]) = new Monoid[MaxMaybe[A]] {
    def zero: MaxMaybe[A] = Tag(empty)

    def append(f1: MaxMaybe[A], f2: => MaxMaybe[A]) = Tag( (Tag unwrap f1, Tag unwrap f2) match {
      case (Just(v1), Just(v2)) => Just(Order[A].max(v1, v2))
      case (_f1 @ Just(_), Empty()) => _f1
      case (Empty(), _f2 @ Just(_)) => _f2
      case (Empty(), Empty()) => Empty()
    })
  }

  implicit def maybeMaxShow[A: Show]: Show[MaxMaybe[A]] = Tag.subst(Show[Maybe[A]])

  implicit def maybeMaxOrder[A: Order]: Order[MaxMaybe[A]] = Tag.subst(Order[Maybe[A]])

  implicit def maybeMaxMonad: Monad[MaxMaybe] = Tags.Max.subst1[Monad, Maybe](Monad[Maybe])

  implicit val maybeInstance: Traverse[Maybe] with MonadPlus[Maybe] with BindRec[Maybe] with Cozip[Maybe] with Zip[Maybe] with Unzip[Maybe] with Align[Maybe] with IsEmpty[Maybe] with Cobind[Maybe] with Optional[Maybe] =
    new Traverse[Maybe] with MonadPlus[Maybe] with BindRec[Maybe] with Cozip[Maybe] with Zip[Maybe] with Unzip[Maybe] with Align[Maybe] with IsEmpty[Maybe] with Cobind[Maybe] with Optional[Maybe] {

      def point[A](a: => A) = just(a)

      override def ap[A, B](fa: => Maybe[A])(mf: => Maybe[A => B]) =
        mf.cata(f => fa.cata(f andThen just, empty), empty)

      def bind[A, B](fa: Maybe[A])(f: A => Maybe[B]) = fa flatMap f

      @scala.annotation.tailrec
      def tailrecM[A, B](f: A => Maybe[A \/ B])(a: A): Maybe[B] =
        f(a) match {
          case Empty() => Empty()
          case Just(-\/(a)) => tailrecM(f)(a)
          case Just(\/-(b)) => Just(b)
        }

      override def map[A, B](fa: Maybe[A])(f: A => B) = fa map f

      def traverseImpl[F[_], A, B](fa: Maybe[A])(f: A => F[B])(implicit F: Applicative[F]) =
        fa.cata(a => F.map(f(a))(just), F.point(empty))

      def empty[A]: Maybe[A] = Maybe.empty

      def plus[A](a: Maybe[A], b: => Maybe[A]) = a orElse b

      override def foldRight[A, B](fa: Maybe[A], z: => B)(f: (A, => B) => B) =
        fa.cata(f(_, z), z)

      def cozip[A, B](fa: Maybe[A \/ B]) =
        fa.cata(_.leftMap(just).map(just), -\/(empty))

      def zip[A, B](a: => Maybe[A], b: => Maybe[B]) = a.zip(b)

      def unzip[A, B](a: Maybe[(A, B)]) =
        a.cata(ab => (just(ab._1), just(ab._2)), (empty, empty))

      def alignWith[A, B, C](f: A \&/ B => C) = (fa, fb) =>
        fa.cata(
          a => fb.cata(
            b => just(f(\&/.Both(a, b))),
            just(f(\&/.This(a)))),
          fb.cata(
            b => just(f(\&/.That(b))),
            empty))

      def cobind[A, B](fa: Maybe[A])(f: Maybe[A] => B) =
        fa.cobind(f)

      override def cojoin[A](a: Maybe[A]) =
        a.cojoin

      def pextract[B, A](fa: Maybe[A]): Maybe[B] \/ A =
        fa.cata(\/.right, -\/(empty))

      override def isDefined[A](fa: Maybe[A]): Boolean = fa.isJust

      override def toOption[A](fa: Maybe[A]): Option[A] = fa.toOption

      override def toMaybe[A](fa: Maybe[A]) = fa

      override def filter[A](fa: Maybe[A])(f: A => Boolean): Maybe[A] =
        fa.filter(f)
    }
}

private sealed trait MaybeEqual[A] extends Equal[Maybe[A]] {
  implicit def A: Equal[A]

  override final def equal(fa1: Maybe[A], fa2: Maybe[A]) =
    fa1.cata(
      a1 => fa2.cata(a2 => A.equal(a1, a2), false),
      fa2.cata(_ => false, true))
}

Other Scala examples (source code examples)

Here is a short list of links related to this Scala Maybe.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.