All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scalaz.Maybe.scala Maven / Gradle / Ivy

The newest version!
package scalaz

import scala.annotation.tailrec
import scala.util.control.NonFatal
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]): 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)

  final def getOrElseF[F[_]: Applicative](fa: => F[A]): F[A] =
    cata(Applicative[F].point[A](_), fa)

  /** 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: ApplicativePlus[F]): F[A] =
    cata(F.point(_), F.empty)

  final def orError[F[_], E](e: E)(implicit F: MonadError[F, E]): F[A] =
    cata(F.point(_), F.raiseError(e))

}

object Maybe extends MaybeInstances {

  final case class Empty[A] private() extends Maybe[A]
  object Empty {
    // https://github.com/scala/bug/issues/11953
    private[this] val value = new Empty[Nothing]
    def apply[A](): Maybe[A] = value.asInstanceOf[Empty[A]]
  }

  // `get` is an intentional name as it is expected by the unapply
  // logic in the scalac pattern matcher.
  final case class Just[A](get: 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)

  /**
   * For interfacing with legacy, deterministic, partial functions. See
   * [[\/.attempt]] for further details.
   */
  def attempt[T](a: => T): Maybe[T] = try {
    just(a)
  } catch {
    case NonFatal(_) => empty
  }

}

sealed abstract class MaybeInstances1 {
  implicit def maybeBand[A: Band]: Band[Maybe[A]] =
    new MaybeMonoid[A] with Band[Maybe[A]] {
      override def A = implicitly
    }
}

sealed abstract class MaybeInstances0 extends MaybeInstances1 {
  implicit def maybeSemiLattice[A](implicit A: SemiLattice[A]): SemiLattice[Maybe[A]] =
    new SemiLattice[Maybe[A]] with Band[Maybe[A]] {
      override def append(fa1: Maybe[A], fa2: => Maybe[A]) =
        fa1.cata(
          a1 => fa2.cata(a2 => Maybe.just(A.append(a1, a2)), fa1),
          fa2.cata(_ => fa2, Maybe.empty))
    }
}

sealed abstract class MaybeInstances extends MaybeInstances0 {
  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]] = {
    import scalaz.syntax.show._
    Show.show(_.cata(
      a => cord"Just($a)",
      Cord("Empty")))
  }

  implicit def maybeMonoid[A: Semigroup]: Monoid[Maybe[A]] =
    new MaybeMonoid[A] {
      override def A = implicitly
    }

  implicit def maybeFirstMonoid[A]: Monoid[FirstMaybe[A]] & Band[FirstMaybe[A]] = new Monoid[FirstMaybe[A]] with Band[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]] & Band[LastMaybe[A]] = new Monoid[LastMaybe[A]] with Band[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]): Monoid[MinMaybe[A]] & Band[MinMaybe[A]] = new Monoid[MinMaybe[A]] with Band[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]): Monoid[MaxMaybe[A]] & Band[MaxMaybe[A]] = new Monoid[MaxMaybe[A]] with Band[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 def maybeIsCovariant: IsCovariant[Maybe] =
    IsCovariant.force[Maybe]

  implicit val maybeInstance: Traverse[Maybe] & MonadPlus[Maybe] & Alt[Maybe] & BindRec[Maybe] & Cozip[Maybe] & Zip[Maybe] & Unzip[Maybe] & Align[Maybe] & IsEmpty[Maybe] & Cobind[Maybe] & Optional[Maybe] =
    new Traverse[Maybe] with MonadPlus[Maybe] with Alt[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

      @tailrec def tailrecM[A, B](a: A)(f: A => Maybe[A \/ B]): Maybe[B] =
        f(a) match {
          case Empty() => Empty()
          case Just(-\/(a)) => tailrecM(a)(f)
          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 unfoldrPsumOpt[S, A](seed: S)(f: S => Maybe[(Maybe[A], S)]): Maybe[Maybe[A]] = {
        @tailrec def go(s: S): Maybe[A] = f(s) match {
          case Just((ma, s)) => ma match {
            case a @ Just(_) => a
            case _ => go(s)
          }
          case Empty() => Empty()
        }
        f(seed) map { case (ma, s) => ma match {
          case a @ Just(_) => a
          case Empty() => go(s)
        }}
      }

      override def unfoldrOpt[S, A, B](seed: S)(f: S => Maybe[(Maybe[A], S)])(implicit r: Reducer[A, B]): Maybe[Maybe[B]] = {
        @tailrec def go(acc: B, s: S): Maybe[B] = f(s) match {
          case Just((ma, s)) => ma match {
            case Just(a) => go(r.snoc(acc, a), s)
            case _ => Empty()
          }
          case _ => Just(acc)
        }
        f(seed) map { case (ma, s) => ma match {
          case Just(a) => go(r.unit(a), s)
          case _ => Empty()
        }}
      }

      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)

      override def alt[A](a1: => Maybe[A], a2: => Maybe[A]): Maybe[A] = a1 orElse a2

      // performance optimisation
      override def altly2[Z, A1, A2](a1: => Maybe[A1], a2: => Maybe[A2])(f: A1 \/ A2 => Z): Maybe[Z] = a1 match {
          case Empty() => a2 match {
            case Empty() => Empty()
            case j => j.map(s => f(\/-(s)))
          }
          case j => j.map(s => f(-\/(s)))
        }

      // performance optimisation
      override def apply2[A, B, C](fa: => Maybe[A], fb: => Maybe[B])(f: (A, B) => C): Maybe[C] =
        fa.flatMap(a => fb.map(b => f(a, b)))
    }
}

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))
}

private sealed trait MaybeMonoid[A] extends Monoid[Maybe[A]] {
  protected def A: Semigroup[A]

  override def append(fa1: Maybe[A], fa2: => Maybe[A]) =
    fa1.cata(
      a1 => fa2.cata(a2 => Maybe.just(A.append(a1, a2)), fa1),
      fa2.cata(_ => fa2, Maybe.empty))

  override def zero = Maybe.empty
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy