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

scalaz.LazyEitherT.scala Maven / Gradle / Ivy

The newest version!
package org.specs2.internal.scalaz

sealed trait LazyEitherT[F[+_], +A, +B] {
  def run: F[LazyEither[A, B]]

  import LazyEither._
  import LazyEitherT._
  import EitherT._
  import OptionT._
  import LazyOptionT._

  def ?[X](left: => X, right: => X)(implicit F: Functor[F]): F[X] =
    F.map(run)(_.fold(_ => left, _ => right))

  def isLeft(implicit F: Functor[F]): F[Boolean] =
    F.map(run)(_.isLeft)

  def isRight(implicit F: Functor[F]): F[Boolean] =
    F.map(run)(_.isRight)

  def swap(implicit F: Functor[F]): F[LazyEither[B, A]] =
    F.map(run)(_.swap)

  def getOrElse[BB >: B](default: => BB)(implicit F: Functor[F]): F[BB] =
    F.map(run)(_ getOrElse default)

  def exists(f: (=> B) => Boolean)(implicit F: Functor[F]): F[Boolean] =
    F.map(run)(_ exists f)

  def forall(f: (=> B) => Boolean)(implicit F: Functor[F]): F[Boolean] =
    F.map(run)(_ forall f)

  def orElse[AA >: A, BB >: B](x: => LazyEitherT[F, AA, BB])(implicit m: Bind[F]): LazyEitherT[F, AA, BB] = {
    val g = run
    LazyEitherT(m.bind(g)(_.fold(
      _ => x.run
      , _ => g
    )))
  }

  def toLazyOption(implicit F: Functor[F]): LazyOptionT[F, B] =
    lazyOptionT(F.map(run)(_ toLazyOption))

  def toOption(implicit F: Functor[F]): OptionT[F, B] =
    optionT(F.map(run)(_ toOption))

  def toList(implicit F: Functor[F]): F[List[B]] =
    F.map(run)(_ toList)

  def toStream(implicit F: Functor[F]): F[Stream[B]] =
    F.map(run)(_ toStream)

  def map[C](f: (=> B) => C)(implicit F: Functor[F]): LazyEitherT[F, A, C] =
    lazyEitherT(F.map(run)(_ map f))

  def foreach(f: (=> B) => Unit)(implicit e: Each[F]): Unit =
    e.each(run)(_ foreach f)

  def flatMap[AA >: A, C](f: (=> B) => LazyEitherT[F, AA, C])(implicit M: Monad[F]): LazyEitherT[F, AA, C] =
    lazyEitherT(M.bind(run)(_.fold(a => M.point(lazyLeft[C](a)), b => f(b).run)))

  def bimap[C, D](f: (=> A) => C, g: (=> B) => D)(implicit F: Functor[F]): LazyEitherT[F, C, D] =
    map(g).left.map(f)

  def bitraverse[G[_], C, D](f: (A) => G[C], g: (B) => G[D])(implicit F: Traverse[F], G: Applicative[G]): G[LazyEitherT[F, C, D]] = {
    import std.either.eitherInstance
    Applicative[G].map(F.traverse(run)(Bitraverse[LazyEither].bitraverseF(f, g)))(LazyEitherT(_: F[LazyEither[C, D]]))
  }

  def traverse[G[_], AA >: A, C](f: (B) => G[C])(implicit F: Traverse[F], G: Applicative[G]): G[LazyEitherT[F, AA, C]] = {
    G.map(F.traverse(run)(o => LazyEither.lazyEitherInstance[A].traverse(o)(f)))(LazyEitherT(_))
  }

  def foldRight[Z](z: => Z)(f: (B, => Z) => Z)(implicit F: Foldable[F]): Z = {
    F.foldr[LazyEither[A, B], Z](run, z)(a => b => LazyEither.lazyEitherInstance[A].foldRight[B, Z](a, b)(f))
  }

  def ap[AA >: A, C](f: => LazyEitherT[F, AA, B => C])(implicit F: Applicative[F]): LazyEitherT[F, AA, C] = {
    // TODO check laziness
    LazyEitherT[F, AA, C](F.apply2(f.run, run)((ff: LazyEither[AA, B => C], aa: LazyEither[A, B]) => LazyEither.lazyEitherInstance[AA].ap(aa)(ff)))
  }

  def left: LeftProjectionT[F, A, B] = new LazyEitherT.LeftProjectionT[F, A, B]() {
    val lazyEitherT = LazyEitherT.this
  }
}

object LazyEitherT extends LazyEitherTFunctions with LazyEitherTInstances {
  def apply[F[+_], A, B](a: F[LazyEither[A, B]]): LazyEitherT[F, A, B] =
    lazyEitherT(a)

  sealed trait LeftProjectionT[F[+_], +A, +B] {
    def lazyEitherT: LazyEitherT[F, A, B]

    import OptionT._
    import LazyOptionT._

    def getOrElse[AA >: A](default: => AA)(implicit F: Functor[F]): F[AA] =
      F.map(lazyEitherT.run)(_.left getOrElse default)

    def exists(f: (=> A) => Boolean)(implicit F: Functor[F]): F[Boolean] =
      F.map(lazyEitherT.run)(_.left exists f)

    def forall(f: (=> A) => Boolean)(implicit F: Functor[F]): F[Boolean] =
      F.map(lazyEitherT.run)(_.left forall f)

    def orElse[AA >: A, BB >: B](x: => LazyEitherT[F, AA, BB])(implicit m: Bind[F]): LazyEitherT[F, AA, BB] = {
      val g = lazyEitherT.run
      LazyEitherT(m.bind(g)((z: LazyEither[A, B]) => z.fold(
        _ => g
        , _ => x.run
      )))
    }

    def toLazyOption(implicit F: Functor[F]): LazyOptionT[F, A] =
      lazyOptionT(F.map(lazyEitherT.run)(_.left toLazyOption))

    def toOption(implicit F: Functor[F]): OptionT[F, A] =
      optionT(F.map(lazyEitherT.run)(_.left toOption))

    def toList(implicit F: Functor[F]): F[List[A]] =
      F.map(lazyEitherT.run)(_.left toList)

    def toStream(implicit F: Functor[F]): F[Stream[A]] =
      F.map(lazyEitherT.run)(_.left toStream)

    def map[C](f: (=> A) => C)(implicit F: Functor[F]): LazyEitherT[F, C, B] =
      LazyEitherT(F.map(lazyEitherT.run)(_.left map f))

    def foreach(f: (=> A) => Unit)(implicit F: Each[F]): Unit =
      F.each(lazyEitherT.run)(_.left foreach f)

    def flatMap[BB >: B, C](f: (=> A) => LazyEitherT[F, C, BB])(implicit M: Monad[F]): LazyEitherT[F, C, BB] =
      LazyEitherT(M.bind(lazyEitherT.run)(_.fold(a => f(a).run, b => M.point(LazyEither.lazyRight[C](b)))))
  }

}

trait LazyEitherTInstances3 {
  implicit def lazyEitherTFunctor[F[+_], L](implicit F0: Functor[F]) = new LazyEitherTFunctor[F, L] {
    implicit def F = F0
  }
  implicit def lazyEitherTLeftProjectionFunctor[F[+_], L](implicit F0: Functor[F]) = new IsomorphismFunctor[({type λ[α] = LazyEitherT.LeftProjectionT[F, L, α]})#λ, ({type λ[α] = LazyEitherT[F, L, α]})#λ] {
    implicit def G = lazyEitherTFunctor[F, L]
    def iso = LazyEitherT.lazyEitherTLeftProjectionEIso2[F, L]
  }
}

trait LazyEitherTInstances2 extends LazyEitherTInstances3 {
  implicit def lazyEitherTPointed[F[+_], L](implicit F0: Pointed[F]) = new LazyEitherTPointed[F, L] {
    implicit def F = F0
  }
  implicit def lazyEitherTLeftProjectionPointed[F[+_], L](implicit F0: Pointed[F]) = new IsomorphismPointed[({type λ[α] = LazyEitherT.LeftProjectionT[F, L, α]})#λ, ({type λ[α] = LazyEitherT[F, L, α]})#λ] {
    implicit def G = lazyEitherTPointed[F, L]
    def iso = LazyEitherT.lazyEitherTLeftProjectionEIso2[F, L]
  }
}

trait LazyEitherTInstances1 extends LazyEitherTInstances2 {
  implicit def lazyEitherTApplicative[F[+_], L](implicit F0: Applicative[F]) = new LazyEitherTApplicative[F, L] {
    implicit def F = F0
  }
  implicit def lazyEitherTLeftProjectionApplicative[F[+_], L](implicit F0: Applicative[F]) = new IsomorphismApplicative[({type λ[α] = LazyEitherT.LeftProjectionT[F, L, α]})#λ, ({type λ[α] = LazyEitherT[F, L, α]})#λ] {
    implicit def G = lazyEitherTApplicative[F, L]
    def iso = LazyEitherT.lazyEitherTLeftProjectionEIso2[F, L]
  }
}

trait LazyEitherTInstances0 extends LazyEitherTInstances1 {
  implicit def lazyEitherTBifunctor[F[+_]](implicit F0: Functor[F]) = new LazyEitherTBifunctor[F] {
    implicit def F = F0
  }
  implicit def lazyEitherTLeftProjectionBifunctor[F[+_]](implicit F0: Functor[F]) = new IsomorphismBifunctor[({type λ[α, β]=LazyEitherT.LeftProjectionT[F, α, β]})#λ, ({type λ[α, β]=LazyEitherT[F, α, β]})#λ] {
    implicit def G = lazyEitherTBifunctor[F]
    def iso = LazyEitherT.lazyEitherTLeftProjectionIso2[F]
  }

  implicit def lazyEitherTMonad[F[+_], L](implicit F0: Monad[F]) = new LazyEitherTMonad[F, L] {
    implicit def F = F0
  }
  implicit def lazyEitherTLeftProjectionMonad[F[+_], L](implicit F0: Monad[F]) = new IsomorphismMonad[({type λ[α] = LazyEitherT.LeftProjectionT[F, L, α]})#λ, ({type λ[α] = LazyEitherT[F, L, α]})#λ] {
    implicit def G = lazyEitherTMonad[F, L]
    def iso = LazyEitherT.lazyEitherTLeftProjectionEIso2[F, L]
  }
  implicit def lazyEitherTFoldable[F[+_], L](implicit F0: Foldable[F]) = new LazyEitherTFoldable[F, L] {
    implicit def F = F0
  }
  implicit def lazyEitherTLeftProjectionFoldable[F[+_], L](implicit F0: Foldable[F]) = new IsomorphismFoldable[({type λ[α] = LazyEitherT.LeftProjectionT[F, L, α]})#λ, ({type λ[α] = LazyEitherT[F, L, α]})#λ] {
    implicit def G = lazyEitherTFoldable[F, L]
    def iso = LazyEitherT.lazyEitherTLeftProjectionEIso2[F, L]
  }
}

// TODO more instances
trait LazyEitherTInstances extends LazyEitherTInstances0 {
  implicit def lazyEitherTBitraverse[F[+_]](implicit F0: Traverse[F]) = new LazyEitherTBitraverse[F] {
    implicit def F = F0
  }
  implicit def lazyEitherTLeftProjectionBitraverse[F[+_]](implicit F0: Traverse[F]) = new IsomorphismBitraverse[({type λ[α, β] = LazyEitherT.LeftProjectionT[F, α, β]})#λ, ({type λ[α, β] = LazyEitherT[F, α, β]})#λ] {
    implicit def G = lazyEitherTBitraverse[F]
    def iso = LazyEitherT.lazyEitherTLeftProjectionIso2[F]
  }

  implicit def lazyEitherTTraverse[F[+_], L](implicit F0: Traverse[F]) = new LazyEitherTTraverse[F, L] {
    implicit def F = F0
  }

  implicit def lazyEitherTLeftProjectionTraverse[F[+_], L](implicit F0: Traverse[F]) = new IsomorphismTraverse[({type λ[α]=LazyEitherT.LeftProjectionT[F, L, α]})#λ, ({type λ[α]=LazyEitherT[F, L, α]})#λ] {
    implicit def G = lazyEitherTTraverse[F, L]
    def iso = LazyEitherT.lazyEitherTLeftProjectionEIso2[F, L]
  }
}

trait LazyEitherTFunctions {
  def lazyEitherT[F[+_], A, B](a: F[LazyEither[A, B]]): LazyEitherT[F, A, B] = new LazyEitherT[F, A, B] {
    val run = a
  }

  import LazyEither._

  def lazyLeftT[F[+_], A, B](a: => A)(implicit p: Pointed[F]): LazyEitherT[F, A, B] =
    lazyEitherT(p.point(lazyLeft(a)))

  def lazyRightT[F[+_], A, B](b: => B)(implicit p: Pointed[F]): LazyEitherT[F, A, B] =
    lazyEitherT(p.point(lazyRight(b)))

  import Isomorphism.{IsoFunctorTemplate, IsoBifunctorTemplate}

  implicit def lazyEitherTLeftProjectionEIso2[F[+_], E] = new IsoFunctorTemplate[({type λ[α] = LazyEitherT.LeftProjectionT[F, E, α]})#λ, ({type λ[α] = LazyEitherT[F, E, α]})#λ] {
    def to[A](fa: LazyEitherT.LeftProjectionT[F, E, A]): LazyEitherT[F, E, A] = fa.lazyEitherT
    def from[A](ga: LazyEitherT[F, E, A]): LazyEitherT.LeftProjectionT[F, E, A] = ga.left
  }
  implicit def lazyEitherTLeftProjectionIso2[F[+_]] = new IsoBifunctorTemplate[({type λ[α, β] = LazyEitherT.LeftProjectionT[F, α, β]})#λ, ({type λ[α, β] = LazyEitherT[F, α, β]})#λ] {
    def to[A, B](fa: LazyEitherT.LeftProjectionT[F, A, B]): LazyEitherT[F, A, B] = fa.lazyEitherT
    def from[A, B](ga: LazyEitherT[F, A, B]): LazyEitherT.LeftProjectionT[F, A, B] = ga.left
  }
}

//
// Type class implementation traits
//

trait LazyEitherTFunctor[F[+_], E] extends Functor[({type λ[α]=LazyEitherT[F, E, α]})#λ] {
  implicit def F: Functor[F]

  override def map[A, B](fa: LazyEitherT[F, E, A])(f: (A) => B): LazyEitherT[F, E, B] = fa map (a => f(a))
}

trait LazyEitherTPointed[F[+_], E] extends Pointed[({type λ[α]=LazyEitherT[F, E, α]})#λ] with LazyEitherTFunctor[F, E] {
  implicit def F: Pointed[F]

  def point[A](a: => A): LazyEitherT[F, E, A] = LazyEitherT.lazyRightT(a)
}

trait LazyEitherTApplicative[F[+_], E] extends Applicative[({type λ[α]=LazyEitherT[F, E, α]})#λ] with LazyEitherTPointed[F, E] {
  implicit def F: Applicative[F]

  override def ap[A, B](fa: => LazyEitherT[F, E, A])(f: => LazyEitherT[F, E, (A) => B]): LazyEitherT[F, E, B] = fa ap f
}

trait LazyEitherTMonad[F[+_], E] extends Monad[({type λ[α]=LazyEitherT[F, E, α]})#λ] with LazyEitherTApplicative[F, E] {
  implicit def F: Monad[F]

  def bind[A, B](fa: LazyEitherT[F, E, A])(f: (A) => LazyEitherT[F, E, B]): LazyEitherT[F, E, B] = fa flatMap (a => f(a))
}

trait LazyEitherTFoldable[F[+_], E] extends Foldable.FromFoldr[({type λ[α]=LazyEitherT[F, E, α]})#λ] {
  implicit def F: Foldable[F]

  def foldRight[A, B](fa: LazyEitherT[F, E, A], z: => B)(f: (A, => B) => B): B = fa.foldRight(z)(f)
}

trait LazyEitherTTraverse[F[+_], E] extends Traverse[({type λ[α]=LazyEitherT[F, E, α]})#λ] with LazyEitherTFoldable[F, E] {
  implicit def F: Traverse[F]

  def traverseImpl[G[_]: Applicative, A, B](fa: LazyEitherT[F, E, A])(f: (A) => G[B]): G[LazyEitherT[F, E, B]] = fa traverse f

  override def foldRight[A, B](fa: LazyEitherT[F, E, A], z: => B)(f: (A, => B) => B): B = fa.foldRight(z)(f)
}

trait LazyEitherTBifunctor[F[+_]] extends Bifunctor[({type λ[α, β] = LazyEitherT[F, α, β]})#λ] {
  implicit def F: Functor[F]

  def bimap[A, B, C, D](fab: LazyEitherT[F, A, B])(f: A => C, g: B => D) =
    fab.map(x => g(x)).left.map(x => f(x))
}

trait LazyEitherTBitraverse[F[+_]] extends Bitraverse[({type λ[α, β] = LazyEitherT[F, α, β]})#λ] {
  implicit def F: Traverse[F]

  def bitraverseImpl[G[_]: Applicative, A, B, C, D](fab: LazyEitherT[F, A, B])(f: (A) => G[C], g: (B) => G[D]): G[LazyEitherT[F, C, D]] =
    Applicative[G].map(F.traverse(fab.run)(Bitraverse[LazyEither].bitraverseF(f, g)))(LazyEitherT.lazyEitherT(_))
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy