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

scalaz.LazyOption.scala Maven / Gradle / Ivy

The newest version!
package scalaz

/** [[scala.Option]], but with a value by name. */
sealed abstract class LazyOption[A] extends Product with Serializable {

  import LazyOption._
  import LazyEither._
//  import newtypes.{FirstLazyOption, LastLazyOption}

  def fold[X](some: (=> A) => X, none: => X): X =
    this match {
      case LazySome(z) => some(z())
      case LazyNone()  => none
    }

  def ?[X](some: => X, none: => X): X =
    fold(_ => some, none)

  def isDefined: Boolean =
    fold(_ => true, false)

  def isEmpty: Boolean =
    !isDefined

  def getOrElse[AA >: A](default: => AA): AA =
    fold(a => a, default)

  def |[AA >: A](default: => AA): AA =
    getOrElse(default)

  def exists(f: (=> A) => Boolean): Boolean =
    fold(f, false)

  def forall(f: (=> A) => Boolean): Boolean =
    fold(f, true)

  def toOption: Option[A] =
    fold(a => Some(a), None)

  def toLazyRight[X](left: => X): LazyEither[X, A] =
    fold(lazyRight(_), lazyLeft(left))

  def toLazyLeft[X](right: => X): LazyEither[A, X] =
    fold(lazyLeft(_), lazyRight(right))

  def toRight[X](left: => X): (X \/ A) =
    fold(\/-(_), -\/(left))

  def toLeft[X](right: => X): (A \/ X) =
    fold(-\/(_), \/-(right))

  def toList: List[A] =
    fold(_ :: Nil, Nil)

  def orElse(a: => LazyOption[A]): LazyOption[A] =
    fold(_ => this, a)

/* TODO
  def first: FirstLazyOption[A] =
    this.*-->[FirstLazyOption[A]]

  def last: LastLazyOption[A] =
    this.*-->[LastLazyOption[A]]
*/

  def map[B](f: (=> A) => B): LazyOption[B] =
    fold(a => lazySome(f(a)), lazyNone)

  def foreach(f: (=> A) => Unit): Unit =
    fold(f, ())

  def filter(f: (=> A) => Boolean): LazyOption[A] =
    fold(a => if (f(a)) this else lazyNone, lazyNone)

  def flatMap[B](f: (=> A) => LazyOption[B]): LazyOption[B] =
    fold(f, lazyNone)

  def ap[B](f: => LazyOption[A => B]): LazyOption[B] =
    fold(a => f map (_.apply(a)), lazyNone)

  def traverse[G[_] : Applicative, B](f: (=> A) => G[B]): G[LazyOption[B]] =
    fold(
      some = x => Applicative[G].map(f(x))(b => lazySome(b)),
      none = Applicative[G].point(lazyNone[B])
    )

  def foldRight[B](z: => B)(f: (A, => B) => B): B =
    fold(
      some = a => f(a, z),
      none = z
    )

  def zip[B](b: => LazyOption[B]): LazyOption[(A, B)] =
    for {
      x <- this
      y <- b
    } yield (x, y)

  def unzip[X, Y](implicit ev: A <:< (X, Y)): (LazyOption[X], LazyOption[Y]) =
    fold(xy => (lazySome(xy._1), lazySome(xy._2)), (lazyNone, lazyNone))

}

private final case class LazySome[A](a: () => A) extends LazyOption[A]

private final case class LazyNone[A] private() extends LazyOption[A]

private object LazyNone {
  private[scalaz] val none = LazyNone[Any]()
}

sealed abstract class LazyOptionInstances {
  import LazyOption._

  implicit val lazyOptionIsCovariant: IsCovariant[LazyOption] =
    IsCovariant.force[LazyOption]

  implicit val lazyOptionInstance: Traverse[LazyOption] & MonadPlus[LazyOption] & Alt[LazyOption] & BindRec[LazyOption] & Cozip[LazyOption] & Zip[LazyOption] & Unzip[LazyOption] & Align[LazyOption] & Cobind[LazyOption] & Optional[LazyOption] & IsEmpty[LazyOption] =
    new Traverse[LazyOption] with MonadPlus[LazyOption] with Alt[LazyOption] with BindRec[LazyOption] with Cozip[LazyOption] with Zip[LazyOption] with Unzip[LazyOption] with Align[LazyOption] with Cobind[LazyOption] with Optional[LazyOption] with IsEmpty[LazyOption] {
      def cobind[A, B](fa: LazyOption[A])(f: LazyOption[A] => B): LazyOption[B] = map(cojoin(fa))(f)
      override def cojoin[A](a: LazyOption[A]) = a match {
        case LazyNone() => lazyNone
        case o @ LazySome(_) => LazySome(() => o)
      }
      def traverseImpl[G[_]: Applicative, A, B](fa: LazyOption[A])(f: A => G[B]): G[LazyOption[B]] = fa traverse (a => f(a))
      override def foldRight[A, B](fa: LazyOption[A], z: => B)(f: (A, => B) => B): B = fa.foldRight(z)(f)
      override def ap[A, B](fa: => LazyOption[A])(f: => LazyOption[A => B]): LazyOption[B] = fa ap f
      def plus[A](a: LazyOption[A], b: => LazyOption[A]): LazyOption[A] = a orElse b
      def alt[A](a: => LazyOption[A], b: => LazyOption[A]): LazyOption[A] = plus(a, b)
      def bind[A, B](fa: LazyOption[A])(f: A => LazyOption[B]): LazyOption[B] = fa flatMap (a => f(a))
      def point[A](a: => A): LazyOption[A] = lazySome(a)
      def empty[A]: LazyOption[A] = lazyNone
      def cozip[A, B](a: LazyOption[A \/ B]) =
        a.fold({
          case -\/(a) => -\/(lazySome(a))
          case \/-(b) => \/-(lazySome(b))
        }, -\/(lazyNone))
      def zip[A, B](a: => LazyOption[A], b: => LazyOption[B]) = a zip b
      def unzip[A, B](a: LazyOption[(A, B)]) = a.unzip

      def alignWith[A, B, C](f: A \&/ B => C) = (a, b) =>
        a.fold(
          aa => lazySome(f(b.fold(
            bb => \&/.Both(aa, bb), \&/.This(aa)))), b.fold(
            bb => lazySome(f(\&/.That(bb))), lazyNone))

      def pextract[B, A](fa: LazyOption[A]): LazyOption[B] \/ A =
        fa.fold(a => \/-(a), -\/(lazyNone))
      override def isDefined[A](fa: LazyOption[A]): Boolean = fa.isDefined

      @scala.annotation.tailrec
      def tailrecM[A, B](a: A)(f: A => LazyOption[A \/ B]): LazyOption[B] =
        f(a) match {
          case LazyNone() => lazyNone
          case LazySome(t) => t() match {
            case \/-(b) => lazySome(b)
            case -\/(a0) => tailrecM(a0)(f)
          }
        }
    }

  implicit def lazyOptionEqual[A: Equal]: Equal[LazyOption[A]] = {
    import std.option._
    Equal.equalBy(_.toOption)
  }

  implicit def lazyOptionMonoid[A: Semigroup]: Monoid[LazyOption[A]] =
    new Monoid[LazyOption[A]] {
      def zero = lazyNone

      def append(a: LazyOption[A], b: => LazyOption[A]) = (a, b) match {
        case (LazySome(a1), LazySome(b1))     => LazySome(() => Semigroup[A].append(a1(), b1()))
        case (LazySome(_) , LazyNone())       => a
        case (LazyNone()  , b1 @ LazySome(_)) => b1
        case (LazyNone()  , LazyNone())       => lazyNone
      }
    }

  implicit def lazyOptionShow[A](implicit S: Show[A]): Show[LazyOption[A]] =
    Show.shows(_.fold(a => "LazySome(%s)".format(S.shows(a)), "LazyNone"))

  /* TODO
implicit def LazyOptionOrder[A: Order]: Order[LazyOption[A]] =
  Order.orderBy(_.toOption)*/
}

object LazyOption extends LazyOptionInstances {

  def lazySome[A](a: => A): LazyOption[A] =
    LazySome(() => a)

  def lazyNone[A]: LazyOption[A] =
    LazyNone.none.asInstanceOf[LazyOption[A]]

  def fromOption[A](oa: Option[A]): LazyOption[A] = oa match {
    case Some(x) => lazySome(x)
    case None    => lazyNone[A]
  }

  /**
   * Returns the given argument in `lazySome` if this is `true`, `lazyNone` otherwise.
   */
  def condLazyOption[A](value: Boolean, a: => A): LazyOption[A] = if (value) lazySome(a) else lazyNone
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy