package scalaz /** [[scala.Option]], but with a value by name. */ sealed trait LazyOption[+A] { 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 = fold(_ => true, false) def isEmpty = !isDefined def getOrElse[AA >: A](default: => AA): AA = fold(a => a, 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(List(_), Nil) def orElse[AA >: A](a: => LazyOption[AA]): LazyOption[AA] = 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 (k => k.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 case class LazySome[A](a: () => A) extends LazyOption[A] private case object LazyNone extends LazyOption[Nothing] object LazyOption extends LazyOptionFunctions with LazyOptionInstances trait LazyOptionInstances { import LazyOption._ implicit val lazyOptionInstance: Traverse[LazyOption] with MonadPlus[LazyOption] with Cozip[LazyOption] with Zip[LazyOption] with Unzip[LazyOption] = new Traverse[LazyOption] with MonadPlus[LazyOption] with Cozip[LazyOption] with Zip[LazyOption] with Unzip[LazyOption] { 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 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 } implicit def lazyOptionEqual[A: Equal]: Equal[LazyOption[A]] = { import std.option._ Equal.equalBy(_.toOption) } /* TODO implicit def LazyOptionShow[A: Show]: Show[LazyOption[A]] = Show[A].shows(_ map (Show[A].shows(_)) fold ("~Some(" + _ + ")", "~None")) implicit def LazyOptionOrder[A: Order]: Order[LazyOption[A]] = Order.orderBy(_.toOption)*/ } trait LazyOptionFunctions { def lazySome[A](a: => A): LazyOption[A] = LazySome(() => a) def lazyNone[A]: LazyOption[A] = LazyNone 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 }