hael.jjm-core_2.13.0.2.3.source-code.OrWrapped.scala Maven / Gradle / Ivy
The newest version!
package jjm
import cats.~>
import cats.Applicative
import cats.Monad
import cats.StackSafeMonad
import cats.implicits._
import monocle.Iso
import monocle.macros.GenPrism
sealed trait OrWrapped[F[_], A] {
import OrWrapped._
def cata[B](pure: A => B, wrapped: F[A] => B): B = this match {
case Pure(a) => pure(a)
case Wrapped(fa) => wrapped(fa)
}
def wrap(f: A => F[A]): F[A] = cata(f, identity)
def wrapPure(implicit A: Applicative[F]): F[A] = cata(A.pure, identity)
def mapK[G[_]](f: F ~> G): OrWrapped[G, A] = cata(
OrWrapped.pure[G](_),
fa => OrWrapped.wrapped[G, A](f(fa))
)
}
object OrWrapped {
def mapK[F[_], G[_]](f: F ~> G): OrWrapped[F, *] ~> OrWrapped[G, *] =
λ[OrWrapped[F, *] ~> OrWrapped[G, *]](_.mapK(f))
case class Pure[F[_], A](value: A) extends OrWrapped[F, A]
object Pure {
def value[F[_], A] = Iso[Pure[F, A], A](_.value)(Pure.apply[F, A])
}
case class Wrapped[F[_], A](wrappedValue: F[A]) extends OrWrapped[F, A]
object Wrapped {
def wrappedValue[F[_], A] = Iso[Wrapped[F, A], F[A]](_.wrappedValue)(Wrapped.apply[F, A])
}
def pure[F[_], A] = GenPrism[OrWrapped[F, A], Pure[F, A]].composeIso(Pure.value)
def wrapped[F[_], A] = GenPrism[OrWrapped[F, A], Wrapped[F, A]].composeIso(Wrapped.wrappedValue)
def pure[F[_]] = new PureBuilder[F]
class PureBuilder[F[_]] {
def apply[A](value: A): OrWrapped[F, A] = Pure[F, A](value)
}
// TODO is this actually stack-safe? why did I do this instead of implementing tailRecM?
implicit def catsOrWrappedMonad[F[_]: Monad]: Monad[OrWrapped[F, *]] =
new StackSafeMonad[OrWrapped[F, *]] {
override def pure[A](a: A): OrWrapped[F, A] = OrWrapped.pure[F](a)
override def flatMap[A, B](
owa: OrWrapped[F, A])(
f: A => OrWrapped[F, B]
): OrWrapped[F, B] = owa.cata(
f, (fa: F[A]) => OrWrapped.wrapped(fa.flatMap(a => f(a).wrapPure))
)
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy