All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
aecor.data.Folded.scala Maven / Gradle / Ivy
package aecor.data
import aecor.data.Folded.{ Impossible, Next }
import cats.kernel.{ Eq, Monoid, Semigroup }
import cats.{ Alternative, Applicative, CoflatMap, Eval, MonadError, Now, Show, Traverse }
import scala.annotation.tailrec
sealed abstract class Folded[+A] extends Product with Serializable { self =>
def fold[B](impossible: => B)(next: A => B): B = this match {
case Impossible => impossible
case Next(a) => next(a)
}
def map[B](f: A => B): Folded[B] = this match {
case Impossible => Impossible
case Next(a) => Next(f(a))
}
def flatMap[B](f: A => Folded[B]): Folded[B] = this match {
case Impossible => Impossible
case Next(a) => f(a)
}
def getOrElse[AA >: A](that: => AA): AA = this match {
case Impossible => that
case Next(a) => a
}
def orElse[AA >: A](that: Folded[AA]): Folded[AA] = this match {
case Next(_) => this
case Impossible => that
}
def isNext: Boolean = fold(false)(_ => true)
def isImpossible: Boolean = !isNext
def filter(f: A => Boolean): Folded[A] = this match {
case Next(a) if f(a) => this
case _ => Impossible
}
def exists(f: A => Boolean): Boolean = filter(f).isNext
def forall(f: A => Boolean): Boolean = fold(true)(f)
def toOption: Option[A] = fold(Option.empty[A])(Some(_))
def toEither[E](error: => E): Either[E, A] = fold[Either[E, A]](Left(error))(Right(_))
def toMonadError[F[_], E]: ToMonadErrorPartiallyApplied[F, E] =
new ToMonadErrorPartiallyApplied[F, E]
final class ToMonadErrorPartiallyApplied[F[_], E] {
def apply[AA >: A](error: => E)(implicit F: MonadError[F, E]): F[AA] =
self match {
case Next(a) => F.pure(a)
case Folded.Impossible =>
F.raiseError[AA](error)
}
}
}
object Folded extends FoldedInstances {
final case object Impossible extends Folded[Nothing]
final case class Next[+A](a: A) extends Folded[A]
def impossible[A]: Folded[A] = Impossible
def next[A](a: A): Folded[A] = Next(a)
object syntax {
implicit final class FoldedIdOps[A](val a: A) extends AnyVal {
def next: Folded[A] = Folded.next(a)
}
def impossible[A]: Folded[A] = Folded.impossible
}
}
trait FoldedInstances {
implicit val aecorDataInstancesForFolded: Traverse[Folded]
with MonadError[Folded, Unit]
with CoflatMap[Folded]
with Alternative[Folded] =
new Traverse[Folded] with MonadError[Folded, Unit] with CoflatMap[Folded]
with Alternative[Folded] {
def empty[A]: Folded[A] = Impossible
def combineK[A](x: Folded[A], y: Folded[A]): Folded[A] = x orElse y
def pure[A](x: A): Folded[A] = Next(x)
override def map[A, B](fa: Folded[A])(f: A => B): Folded[B] =
fa.map(f)
def flatMap[A, B](fa: Folded[A])(f: A => Folded[B]): Folded[B] =
fa.flatMap(f)
@tailrec
def tailRecM[A, B](a: A)(f: A => Folded[Either[A, B]]): Folded[B] =
f(a) match {
case Impossible => Impossible
case Next(Left(a1)) => tailRecM(a1)(f)
case Next(Right(b)) => Next(b)
}
override def map2[A, B, Z](fa: Folded[A], fb: Folded[B])(f: (A, B) => Z): Folded[Z] =
fa.flatMap(a => fb.map(b => f(a, b)))
override def map2Eval[A, B, Z](fa: Folded[A],
fb: Eval[Folded[B]])(f: (A, B) => Z): Eval[Folded[Z]] =
fa match {
case Impossible => Now(Impossible)
case Next(a) => fb.map(_.map(f(a, _)))
}
def coflatMap[A, B](fa: Folded[A])(f: Folded[A] => B): Folded[B] =
if (fa.isNext) Next(f(fa)) else Impossible
def foldLeft[A, B](fa: Folded[A], b: B)(f: (B, A) => B): B =
fa match {
case Impossible => b
case Next(a) => f(b, a)
}
def foldRight[A, B](fa: Folded[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
fa match {
case Impossible => lb
case Next(a) => f(a, lb)
}
def raiseError[A](e: Unit): Folded[A] = Impossible
def handleErrorWith[A](fa: Folded[A])(f: (Unit) => Folded[A]): Folded[A] = fa orElse f(())
override def traverse[G[_]: Applicative, A, B](fa: Folded[A])(f: A => G[B]): G[Folded[B]] =
fa match {
case Impossible => Applicative[G].pure(Impossible)
case Next(a) => Applicative[G].map(f(a))(Next(_))
}
override def exists[A](fa: Folded[A])(p: A => Boolean): Boolean =
fa.exists(p)
override def forall[A](fa: Folded[A])(p: A => Boolean): Boolean =
fa.forall(p)
override def isEmpty[A](fa: Folded[A]): Boolean =
fa.isImpossible
}
implicit def aecorDataShowForFolded[A](implicit A: Show[A]): Show[Folded[A]] =
new Show[Folded[A]] {
def show(fa: Folded[A]): String = fa match {
case Next(a) => s"Next(${A.show(a)})"
case Impossible => "Impossible"
}
}
implicit def aecorDataMonoidForFolded[A](implicit A: Semigroup[A]): Monoid[Folded[A]] =
new Monoid[Folded[A]] {
def empty = Folded.impossible
def combine(x: Folded[A], y: Folded[A]): Folded[A] =
x match {
case Impossible => y
case Next(a) =>
y match {
case Impossible => x
case Next(b) => Next(A.combine(a, b))
}
}
}
implicit def aecorDataEqForFolded[A](implicit A: Eq[A]): Eq[Folded[A]] =
Eq.instance {
case (Next(l), Next(r)) => A.eqv(l, r)
case (Impossible, Impossible) => true
case _ => false
}
}