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

cats.data.Kleisli.scala Maven / Gradle / Ivy

The newest version!
package cats
package data

import cats.{Contravariant, Id}
import cats.arrow._

/**
 * Represents a function `A => F[B]`.
 */
final case class Kleisli[F[_], -A, B](run: A => F[B]) { self =>

  def ap[C, AA <: A](f: Kleisli[F, AA, B => C])(implicit F: Apply[F]): Kleisli[F, AA, C] =
    Kleisli(a => F.ap(f.run(a))(run(a)))

  /**
   * Performs [[local]] and [[map]] simultaneously.
   */
  def dimap[C, D](f: C => A)(g: B => D)(implicit F: Functor[F]): Kleisli[F, C, D] =
    Kleisli(c => F.map(run(f(c)))(g))

  /**
   * Modify the output of the Kleisli function with `f`.
   * {{{
   * scala> import cats.data.Kleisli, cats.implicits._
   * scala> val takeHead = Kleisli[Option, List[Int], Int](_.headOption)
   * scala> takeHead.map(_.toDouble).run(List(1))
   * res0: Option[Double] = Some(1.0)
   * }}}
   */
  def map[C](f: B => C)(implicit F: Functor[F]): Kleisli[F, A, C] =
    Kleisli(a => F.map(run(a))(f))

  def mapF[N[_], C](f: F[B] => N[C]): Kleisli[N, A, C] =
    Kleisli(a => f(run(a)))

  /**
   * Modify the context `F` using transformation `f`.
   */
  def mapK[G[_]](f: F ~> G): Kleisli[G, A, B] =
    Kleisli[G, A, B](a => f(run(a)))

  def flatMap[C, AA <: A](f: B => Kleisli[F, AA, C])(implicit F: FlatMap[F]): Kleisli[F, AA, C] =
    Kleisli.shift(a => F.flatMap[B, C](run(a))((b: B) => f(b).run(a)))

  def flatMapF[C](f: B => F[C])(implicit F: FlatMap[F]): Kleisli[F, A, C] =
    Kleisli.shift(a => F.flatMap(run(a))(f))

  /**
   * Composes [[run]] with a function `B => F[C]` not lifted into Kleisli.
   */
  def andThen[C](f: B => F[C])(implicit F: FlatMap[F]): Kleisli[F, A, C] =
    Kleisli.shift(a => F.flatMap(run(a))(f))

  /**
   * Tip to tail Kleisli arrow composition.
   * Creates a function `A => F[C]` from [[run]] (`A => F[B]`) and the given Kleisli of `B => F[C]`.
   * {{{
   * scala> import cats.data.Kleisli, cats.implicits._
   * scala> val takeHead = Kleisli[Option, List[Int], Int](_.headOption)
   * scala> val plusOne = Kleisli[Option, Int, Int](i => Some(i + 1))
   * scala> (takeHead andThen plusOne).run(List(1))
   * res0: Option[Int] = Some(2)
   * }}}
   */
  def andThen[C](k: Kleisli[F, B, C])(implicit F: FlatMap[F]): Kleisli[F, A, C] =
    this.andThen(k.run)

  def compose[Z, AA <: A](f: Z => F[AA])(implicit F: FlatMap[F]): Kleisli[F, Z, B] =
    Kleisli.shift((z: Z) => F.flatMap(f(z))(run))

  def compose[Z, AA <: A](k: Kleisli[F, Z, AA])(implicit F: FlatMap[F]): Kleisli[F, Z, B] =
    this.compose(k.run)

  def traverse[G[_], AA <: A](f: G[AA])(implicit F: Applicative[F], G: Traverse[G]): F[G[B]] =
    G.traverse(f)(run)

  def lift[G[_]](implicit G: Applicative[G]): Kleisli[λ[α => G[F[α]]], A, B] =
    Kleisli[λ[α => G[F[α]]], A, B](a => Applicative[G].pure(run(a)))

  /**
   * Contramap the input using `f`, where `f` may modify the input type of the Kleisli arrow.
   * {{{
   * scala> import cats.data.Kleisli, cats.implicits._
   * scala> type ParseResult[A] = Either[Throwable, A]
   * scala> val parseInt = Kleisli[ParseResult, String, Int](s => Either.catchNonFatal(s.toInt))
   * scala> parseInt.local[List[String]](_.combineAll).run(List("1", "2"))
   * res0: ParseResult[Int] = Right(12)
   * }}}
   */
  def local[AA](f: AA => A): Kleisli[F, AA, B] =
    Kleisli(aa => run(f(aa)))

  @deprecated("Use mapK", "1.0.0-RC2")
  private[cats] def transform[G[_]](f: FunctionK[F, G]): Kleisli[G, A, B] =
    mapK(f)

  def lower(implicit F: Applicative[F]): Kleisli[F, A, F[B]] =
    Kleisli(a => F.pure(run(a)))

  def first[C](implicit F: Functor[F]): Kleisli[F, (A, C), (B, C)] =
    Kleisli { case (a, c) => F.fproduct(run(a))(_ => c) }

  def second[C](implicit F: Functor[F]): Kleisli[F, (C, A), (C, B)] =
    Kleisli { case (c, a) => F.map(run(a))(c -> _) }

  /** Discard computed B and yield the input value. */
  def tap[AA <: A](implicit F: Functor[F]): Kleisli[F, AA, AA] =
    Kleisli(a => F.as(run(a), a))

  /** Yield computed B combined with input value. */
  def tapWith[C, AA <: A](f: (AA, B) => C)(implicit F: Functor[F]): Kleisli[F, AA, C] =
    Kleisli(a => F.map(run(a))(b => f(a, b)))

  def tapWithF[C, AA <: A](f: (AA, B) => F[C])(implicit F: FlatMap[F]): Kleisli[F, AA, C] =
    Kleisli(a => F.flatMap(run(a))(b => f(a, b)))

  def toReader: Reader[A, F[B]] = Kleisli[Id, A, F[B]](run)

  def apply(a: A): F[B] = run(a)
}

object Kleisli
    extends KleisliInstances
    with KleisliFunctions
    with KleisliFunctionsBinCompat
    with KleisliExplicitInstances {

  /**
   * Internal API — shifts the execution of `run` in the `F` context.
   *
   * Used to build Kleisli values for `F[_]` data types that implement `Monad`,
   * in which case it is safer to trigger the `F[_]` context earlier.
   *
   * The requirement is for `FlatMap` as this will get used in operations
   * that invoke `F.flatMap` (e.g. in `Kleisli#flatMap`). However we are
   * doing discrimination based on inheritance and if we detect an
   * `Applicative`, then we use it to trigger the `F[_]` context earlier.
   *
   * Triggering the `F[_]` context earlier is important to avoid stack
   * safety issues for `F` monads that have a stack safe `flatMap`
   * implementation. For example `Eval` or `IO`. Without this the `Monad`
   * instance is stack unsafe, even if the underlying `F` is stack safe
   * in `flatMap`.
   */
  private[data] def shift[F[_], A, B](run: A => F[B])(implicit F: FlatMap[F]): Kleisli[F, A, B] =
    F match {
      case ap: Applicative[F] @unchecked =>
        Kleisli(r => F.flatMap(ap.pure(r))(run))
      case _ =>
        Kleisli(run)
    }

  /**
   * Creates a `FunctionK` that transforms a `Kleisli[F, A, B]` into an `F[B]` by applying the value of type `a:A`.
   * {{{
   * scala> import cats.{~>}, cats.data.{Kleisli, EitherT}
   *
   * scala> def f(i: Int): Option[Either[Char, Char]] = if (i > 0) Some(Right('n')) else if (i < 0) Some(Left('z')) else None
   *
   * scala> type KOI[A] = Kleisli[Option, Int, A]
   * scala> val b: KOI[Either[Char, Char]] = Kleisli[Option, Int, Either[Char, Char]](f _)
   * scala> val nt: Kleisli[Option, Int, *] ~> Option = Kleisli.applyK[Option, Int](1)
   * scala> nt(b)
   * res0: Option[Either[Char, Char]] = Some(Right(n))
   *
   * scala> type EKOIC[A] = EitherT[KOI, Char, A]
   * scala> val c: EKOIC[Char] = EitherT[KOI, Char, Char](b)
   * scala> c.mapK(nt).value
   * res1: Option[Either[Char, Char]] = Some(Right(n))
   *
   * scala> val ntz = Kleisli.applyK[Option, Int](0)
   * scala> c.mapK(ntz).value
   * res2: Option[Either[Char, Char]] = None
   * }}}
   */
  def applyK[F[_], A](a: A): Kleisli[F, A, *] ~> F =
    λ[Kleisli[F, A, *] ~> F](_.apply(a))

}

sealed private[data] trait KleisliFunctions {

  /**
   * Creates a Kleisli that ignores its input `A` and returns the given `F[B]`.
   * {{{
   * scala> import cats.data.Kleisli, cats.implicits._
   * scala> val takeHead = Kleisli((_:List[Int]).headOption)
   * scala> val makeList = Kleisli.liftF[Option, Unit, List[Int]](Some(List(1,2,3)))
   * scala> (makeList andThen takeHead).run(())
   * res0: Option[Int] = Some(1)
   * }}}
   */
  def liftF[F[_], A, B](x: F[B]): Kleisli[F, A, B] =
    Kleisli(_ => x)

  /**
   * Same as [[liftF]], but expressed as a FunctionK for use with mapK
   * {{{
   * scala> import cats._, data._, implicits._
   * scala> val a: OptionT[Eval, Int] = 1.pure[OptionT[Eval, *]]
   * scala> val b: OptionT[Kleisli[Eval, String, *], Int] = a.mapK(Kleisli.liftK)
   * scala> b.value.run("").value
   * res0: Option[Int] = Some(1)
   * }}}
   */
  def liftK[F[_], A]: F ~> Kleisli[F, A, *] =
    λ[F ~> Kleisli[F, A, *]](Kleisli.liftF(_))

  @deprecated("Use liftF instead", "1.0.0-RC2")
  private[cats] def lift[F[_], A, B](x: F[B]): Kleisli[F, A, B] =
    Kleisli(_ => x)

  /**
   * Creates a Kleisli arrow ignoring its input and lifting the given `B` into applicative context `F`.
   * {{{
   * scala> import cats.data.Kleisli, cats.implicits._
   * scala> val pureOpt = Kleisli.pure[Option, Unit, String]("beam me up!")
   * scala> pureOpt.run(())
   * res0: Option[String] = Some(beam me up!)
   * }}}
   */
  def pure[F[_], A, B](x: B)(implicit F: Applicative[F]): Kleisli[F, A, B] =
    Kleisli(_ => F.pure(x))

  /**
   * Creates a Kleisli arrow which can lift an `A` into applicative context `F`.
   * This is distinct from [[pure]] in that the input is what is lifted (and not ignored).
   * {{{
   * scala> Kleisli.ask[Option, Int].run(1)
   * res0: Option[Int]: Some(1)
   * }}}
   */
  def ask[F[_], A](implicit F: Applicative[F]): Kleisli[F, A, A] =
    Kleisli(F.pure)

  /**
   * Modifies the input environment with `f`, without changing the input type of the Kleisli.
   * {{{
   * scala> import cats.data.Kleisli
   * scala> val takeHead = Kleisli[Option, List[Int], Int](_.headOption)
   * scala> Kleisli.local[Option, Int, List[Int]](1 :: _)(takeHead).run(List(2,3))
   * res0: Option[Int] = Some(1)
   * }}}
   */
  def local[M[_], A, R](f: R => R)(fa: Kleisli[M, R, A]): Kleisli[M, R, A] =
    Kleisli(r => fa.run(f(r)))
}

sealed private[data] trait KleisliFunctionsBinCompat {

  /**
   * Lifts a natural transformation of effects within a Kleisli
   * to a transformation of Kleislis.
   *
   * Equivalent to running `mapK(f) on a Kleisli.
   *
   * {{{
   * scala> import cats._, data._
   * scala> val f: (List ~> Option) = λ[List ~> Option](_.headOption)
   *
   * scala> val k: Kleisli[List, String, Char] = Kleisli(_.toList)
   * scala> k.run("foo")
   * res0: List[Char] = List(f, o, o)
   *
   * scala> val k2: Kleisli[Option, String, Char] = Kleisli.liftFunctionK(f)(k)
   * scala> k2.run("foo")
   * res1: Option[Char] = Some(f)
   * }}}
   * */
  def liftFunctionK[F[_], G[_], A](f: F ~> G): Kleisli[F, A, *] ~> Kleisli[G, A, *] =
    λ[Kleisli[F, A, *] ~> Kleisli[G, A, *]](_.mapK(f))
}

sealed private[data] trait KleisliExplicitInstances {

  def endoSemigroupK[F[_]](implicit FM: FlatMap[F]): SemigroupK[λ[α => Kleisli[F, α, α]]] =
    Compose[Kleisli[F, *, *]].algebraK

  def endoMonoidK[F[_]](implicit M: Monad[F]): MonoidK[λ[α => Kleisli[F, α, α]]] =
    Category[Kleisli[F, *, *]].algebraK
}

sealed abstract private[data] class KleisliInstances extends KleisliInstances0 {
  implicit def catsDataMonadForKleisliId[A]: CommutativeMonad[Kleisli[Id, A, *]] =
    catsDataCommutativeMonadForKleisli[Id, A]

  implicit val catsDataCommutativeArrowForKleisliId: CommutativeArrow[Kleisli[Id, *, *]] =
    catsDataCommutativeArrowForKleisli[Id]

  implicit def catsDataDeferForKleisli[F[_], A](implicit F: Defer[F]): Defer[Kleisli[F, A, *]] =
    new Defer[Kleisli[F, A, *]] {
      def defer[B](fa: => Kleisli[F, A, B]): Kleisli[F, A, B] = {
        lazy val cacheFa = fa
        Kleisli[F, A, B] { a =>
          F.defer(cacheFa.run(a))
        }
      }
    }

  implicit def catsDataFunctorFilterForKleisli[F[_], A](
    implicit ev: FunctorFilter[F]
  ): FunctorFilter[Kleisli[F, A, *]] =
    new KleisliFunctorFilter[F, A] { val FF = ev }
}

sealed abstract private[data] class KleisliInstances0 extends KleisliInstances0_5 {

  implicit def catsDataCommutativeArrowForKleisli[F[_]](
    implicit M: CommutativeMonad[F]
  ): CommutativeArrow[Kleisli[F, *, *]] with ArrowChoice[Kleisli[F, *, *]] =
    new KleisliCommutativeArrow[F] { def F: CommutativeMonad[F] = M }

  implicit def catsDataCommutativeMonadForKleisli[F[_], A](
    implicit F0: CommutativeMonad[F]
  ): CommutativeMonad[Kleisli[F, A, *]] =
    new KleisliMonad[F, A] with CommutativeMonad[Kleisli[F, A, *]] {
      implicit def F: Monad[F] = F0
    }

}

sealed abstract private[data] class KleisliInstances0_5 extends KleisliInstances1 {
  implicit def catsDataMonoidForKleisli[F[_], A, B](implicit FB0: Monoid[F[B]]): Monoid[Kleisli[F, A, B]] =
    new KleisliMonoid[F, A, B] { def FB: Monoid[F[B]] = FB0 }

  implicit def catsDataMonadErrorForKleisli[F[_], A, E](
    implicit ME: MonadError[F, E]
  ): MonadError[Kleisli[F, A, *], E] =
    new KleisliMonadError[F, A, E] { def F: MonadError[F, E] = ME }

  implicit def catsDataArrowChoiceForKleisli[F[_]](implicit M: Monad[F]): ArrowChoice[Kleisli[F, *, *]] =
    new KleisliArrowChoice[F] {
      def F: Monad[F] = M
    }

  implicit def catsDataContravariantMonoidalForKleisli[F[_], A](
    implicit F0: ContravariantMonoidal[F]
  ): ContravariantMonoidal[Kleisli[F, A, *]] =
    new KleisliContravariantMonoidal[F, A] { def F: ContravariantMonoidal[F] = F0 }

  /**
   * Witness for: Kleisli[M, E, A] <-> (E, R) => A
   * if M is Representable
   */
  implicit def catsDataRepresentableForKleisli[M[_], R, E](
    implicit
    R: Representable.Aux[M, R],
    FK: Functor[Kleisli[M, E, *]]
  ): Representable.Aux[Kleisli[M, E, *], (E, R)] = new Representable[Kleisli[M, E, *]] {

    override type Representation = (E, R)

    override val F: Functor[Kleisli[M, E, *]] = FK

    def index[A](f: Kleisli[M, E, A]): Representation => A = {
      case (e, r) => R.index(f.run(e))(r)
    }

    def tabulate[A](f: Representation => A): Kleisli[M, E, A] =
      Kleisli[M, E, A](e => R.tabulate(r => f((e, r))))
  }
}

sealed abstract private[data] class KleisliInstances1 extends KleisliInstances2 {
  implicit def catsDataMonadForKleisli[F[_], A](implicit M: Monad[F]): Monad[Kleisli[F, A, *]] =
    new KleisliMonad[F, A] { def F: Monad[F] = M }

  implicit def catsDataParallelForKleisli[M[_], A](
    implicit P: Parallel[M]
  ): Parallel.Aux[Kleisli[M, A, *], Kleisli[P.F, A, *]] = new Parallel[Kleisli[M, A, *]] {
    type F[x] = Kleisli[P.F, A, x]
    implicit val monadM: Monad[M] = P.monad
    def applicative: Applicative[Kleisli[P.F, A, *]] = catsDataApplicativeForKleisli(P.applicative)
    def monad: Monad[Kleisli[M, A, *]] = catsDataMonadForKleisli

    def sequential: Kleisli[P.F, A, *] ~> Kleisli[M, A, *] =
      λ[Kleisli[P.F, A, *] ~> Kleisli[M, A, *]](_.mapK(P.sequential))

    def parallel: Kleisli[M, A, *] ~> Kleisli[P.F, A, *] =
      λ[Kleisli[M, A, *] ~> Kleisli[P.F, A, *]](_.mapK(P.parallel))
  }

  implicit def catsDataContravariantForKleisli[F[_], C]: Contravariant[Kleisli[F, *, C]] =
    new Contravariant[Kleisli[F, *, C]] {
      override def contramap[A, B](fa: Kleisli[F, A, C])(f: B => A): Kleisli[F, B, C] =
        fa.local(f)
    }
}

sealed abstract private[data] class KleisliInstances2 extends KleisliInstances3 {
  implicit def catsDataAlternativeForKleisli[F[_], A](implicit F0: Alternative[F]): Alternative[Kleisli[F, A, *]] =
    new KleisliAlternative[F, A] { def F: Alternative[F] = F0 }
}

sealed abstract private[data] class KleisliInstances3 extends KleisliInstances4 {
  implicit def catsDataMonoidKForKleisli[F[_], A](implicit F0: MonoidK[F]): MonoidK[Kleisli[F, A, *]] =
    new KleisliMonoidK[F, A] { def F: MonoidK[F] = F0 }

  implicit def catsDataCommutativeFlatMapForKleisli[F[_], A](
    implicit F0: CommutativeFlatMap[F]
  ): CommutativeFlatMap[Kleisli[F, A, *]] =
    new KleisliFlatMap[F, A] with CommutativeFlatMap[Kleisli[F, A, *]] { val F: CommutativeFlatMap[F] = F0 }

  implicit def catsDataChoiceForKleisli[F[_]](implicit M: Monad[F]): Choice[Kleisli[F, *, *]] =
    new KleisliChoice[F] { def F: Monad[F] = M }

  implicit val catsDataChoiceForKleisliId: Choice[Kleisli[Id, *, *]] =
    catsDataChoiceForKleisli[Id]

  implicit def catsDataComposeForKleisli[F[_]](implicit FM: FlatMap[F]): Compose[Kleisli[F, *, *]] =
    new KleisliCompose[F] { def F: FlatMap[F] = FM }

  implicit def catsDataStrongForKleisli[F[_]](implicit F0: Functor[F]): Strong[Kleisli[F, *, *]] =
    new KleisliStrong[F] { def F: Functor[F] = F0 }

  implicit def catsDataSemigroupForKleisli[F[_], A, B](implicit FB0: Semigroup[F[B]]): Semigroup[Kleisli[F, A, B]] =
    new KleisliSemigroup[F, A, B] { def FB: Semigroup[F[B]] = FB0 }
}

sealed abstract private[data] class KleisliInstances4 extends KleisliInstances5 {
  implicit def catsDataSemigroupKForKleisli[F[_], A](implicit F0: SemigroupK[F]): SemigroupK[Kleisli[F, A, *]] =
    new KleisliSemigroupK[F, A] { def F: SemigroupK[F] = F0 }

  implicit def catsDataFlatMapForKleisli[F[_], A](implicit FM: FlatMap[F]): FlatMap[Kleisli[F, A, *]] =
    new KleisliFlatMap[F, A] { def F: FlatMap[F] = FM }

}

sealed abstract private[data] class KleisliInstances5 extends KleisliInstances6 {

  implicit def catsDataApplicativeErrorForKleisli[F[_], E, A](
    implicit F0: ApplicativeError[F, E]
  ): ApplicativeError[Kleisli[F, A, *], E] =
    new KleisliApplicativeError[F, A, E] { def F: ApplicativeError[F, E] = F0 }
}

sealed abstract private[data] class KleisliInstances6 extends KleisliInstances7 {
  implicit def catsDataApplicativeForKleisli[F[_], A](implicit A: Applicative[F]): Applicative[Kleisli[F, A, *]] =
    new KleisliApplicative[F, A] { def F: Applicative[F] = A }
}

sealed abstract private[data] class KleisliInstances7 extends KleisliInstances8 {
  implicit def catsDataApplyForKleisli[F[_], A](implicit A: Apply[F]): Apply[Kleisli[F, A, *]] =
    new KleisliApply[F, A] { def F: Apply[F] = A }
}

sealed abstract private[data] class KleisliInstances8 extends KleisliInstances9 {
  implicit def catsDataDistributiveForKleisli[F[_], R](implicit F0: Distributive[F]): Distributive[Kleisli[F, R, *]] =
    new KleisliDistributive[F, R] with KleisliFunctor[F, R] { implicit def F: Distributive[F] = F0 }
}

sealed abstract private[data] class KleisliInstances9 {
  implicit def catsDataFunctorForKleisli[F[_], A](implicit F0: Functor[F]): Functor[Kleisli[F, A, *]] =
    new KleisliFunctor[F, A] { def F: Functor[F] = F0 }
}

private[data] trait KleisliCommutativeArrow[F[_]]
    extends CommutativeArrow[Kleisli[F, *, *]]
    with KleisliArrowChoice[F] {
  implicit def F: CommutativeMonad[F]
}

private[data] trait KleisliArrowChoice[F[_]]
    extends ArrowChoice[Kleisli[F, *, *]]
    with KleisliCategory[F]
    with KleisliStrong[F] {
  implicit def F: Monad[F]

  def lift[A, B](f: A => B): Kleisli[F, A, B] =
    Kleisli(a => F.pure(f(a)))

  override def split[A, B, C, D](f: Kleisli[F, A, B], g: Kleisli[F, C, D]): Kleisli[F, (A, C), (B, D)] =
    Kleisli { case (a, c) => F.flatMap(f.run(a))(b => F.map(g.run(c))(d => (b, d))) }

  def choose[A, B, C, D](f: Kleisli[F, A, C])(g: Kleisli[F, B, D]): Kleisli[F, Either[A, B], Either[C, D]] =
    Kleisli(
      (fe: Either[A, B]) =>
        fe match {
          case Left(a)  => F.map(f(a))(Left.apply _)
          case Right(b) => F.map(g(b))(Right.apply _)
        }
    )
}

private[data] trait KleisliStrong[F[_]] extends Strong[Kleisli[F, *, *]] {
  implicit def F: Functor[F]

  override def lmap[A, B, C](fab: Kleisli[F, A, B])(f: C => A): Kleisli[F, C, B] =
    fab.local(f)

  override def rmap[A, B, C](fab: Kleisli[F, A, B])(f: B => C): Kleisli[F, A, C] =
    fab.map(f)

  override def dimap[A, B, C, D](fab: Kleisli[F, A, B])(f: C => A)(g: B => D): Kleisli[F, C, D] =
    fab.dimap(f)(g)

  def first[A, B, C](fa: Kleisli[F, A, B]): Kleisli[F, (A, C), (B, C)] =
    fa.first[C]

  override def second[A, B, C](fa: Kleisli[F, A, B]): Kleisli[F, (C, A), (C, B)] =
    fa.second[C]
}

private[data] trait KleisliChoice[F[_]] extends Choice[Kleisli[F, *, *]] with KleisliCategory[F] {
  def choice[A, B, C](f: Kleisli[F, A, C], g: Kleisli[F, B, C]): Kleisli[F, Either[A, B], C] =
    Kleisli(_.fold(f.run, g.run))
}

private[data] trait KleisliCategory[F[_]] extends Category[Kleisli[F, *, *]] with KleisliCompose[F] {
  implicit def F: Monad[F]

  override def id[A]: Kleisli[F, A, A] = Kleisli.ask[F, A]
}

private[data] trait KleisliCompose[F[_]] extends Compose[Kleisli[F, *, *]] {
  implicit def F: FlatMap[F]

  def compose[A, B, C](f: Kleisli[F, B, C], g: Kleisli[F, A, B]): Kleisli[F, A, C] =
    f.compose(g)
}

private[data] trait KleisliSemigroup[F[_], A, B] extends Semigroup[Kleisli[F, A, B]] {
  implicit def FB: Semigroup[F[B]]

  override def combine(a: Kleisli[F, A, B], b: Kleisli[F, A, B]): Kleisli[F, A, B] =
    Kleisli[F, A, B](x => FB.combine(a.run(x), b.run(x)))
}

private[data] trait KleisliMonoid[F[_], A, B] extends Monoid[Kleisli[F, A, B]] with KleisliSemigroup[F, A, B] {
  implicit def FB: Monoid[F[B]]

  override def empty: Kleisli[F, A, B] = Kleisli[F, A, B](_ => FB.empty)
}

sealed private[data] trait KleisliSemigroupK[F[_], A] extends SemigroupK[Kleisli[F, A, *]] {
  implicit def F: SemigroupK[F]

  override def combineK[B](x: Kleisli[F, A, B], y: Kleisli[F, A, B]): Kleisli[F, A, B] =
    Kleisli(a => F.combineK(x.run(a), y.run(a)))
}

sealed private[data] trait KleisliMonoidK[F[_], A] extends MonoidK[Kleisli[F, A, *]] with KleisliSemigroupK[F, A] {
  implicit def F: MonoidK[F]

  override def empty[B]: Kleisli[F, A, B] = Kleisli.liftF(F.empty[B])
}

private[data] trait KleisliAlternative[F[_], A]
    extends Alternative[Kleisli[F, A, *]]
    with KleisliApplicative[F, A]
    with KleisliMonoidK[F, A] {
  implicit def F: Alternative[F]
}

sealed private[data] trait KleisliContravariantMonoidal[F[_], D] extends ContravariantMonoidal[Kleisli[F, D, *]] {
  implicit def F: ContravariantMonoidal[F]

  override def unit: Kleisli[F, D, Unit] = Kleisli(Function.const(F.unit))

  override def contramap[A, B](fa: Kleisli[F, D, A])(f: B => A): Kleisli[F, D, B] =
    Kleisli(d => F.contramap(fa.run(d))(f))

  override def product[A, B](fa: Kleisli[F, D, A], fb: Kleisli[F, D, B]): Kleisli[F, D, (A, B)] =
    Kleisli(d => F.product(fa.run(d), fb.run(d)))
}

private[data] trait KleisliMonadError[F[_], A, E]
    extends MonadError[Kleisli[F, A, *], E]
    with KleisliApplicativeError[F, A, E]
    with KleisliMonad[F, A] {
  def F: MonadError[F, E]
}

private[data] trait KleisliApplicativeError[F[_], A, E]
    extends ApplicativeError[Kleisli[F, A, *], E]
    with KleisliApplicative[F, A] {
  type K[T] = Kleisli[F, A, T]

  implicit def F: ApplicativeError[F, E]

  def raiseError[B](e: E): K[B] = Kleisli(_ => F.raiseError(e))

  def handleErrorWith[B](kb: K[B])(f: E => K[B]): K[B] = Kleisli { (a: A) =>
    F.handleErrorWith(kb.run(a))((e: E) => f(e).run(a))
  }
}

private[data] trait KleisliMonad[F[_], A]
    extends Monad[Kleisli[F, A, *]]
    with KleisliFlatMap[F, A]
    with KleisliApplicative[F, A] {
  implicit def F: Monad[F]
}

private[data] trait KleisliFlatMap[F[_], A] extends FlatMap[Kleisli[F, A, *]] with KleisliApply[F, A] {
  implicit def F: FlatMap[F]

  def flatMap[B, C](fa: Kleisli[F, A, B])(f: B => Kleisli[F, A, C]): Kleisli[F, A, C] =
    fa.flatMap(f)

  def tailRecM[B, C](b: B)(f: B => Kleisli[F, A, Either[B, C]]): Kleisli[F, A, C] =
    Kleisli[F, A, C]({ a =>
      F.tailRecM(b) { f(_).run(a) }
    })
}

private[data] trait KleisliApplicative[F[_], A] extends Applicative[Kleisli[F, A, *]] with KleisliApply[F, A] {
  implicit def F: Applicative[F]

  def pure[B](x: B): Kleisli[F, A, B] =
    Kleisli.pure[F, A, B](x)
}

private[data] trait KleisliApply[F[_], A] extends Apply[Kleisli[F, A, *]] with KleisliFunctor[F, A] {
  implicit def F: Apply[F]

  override def ap[B, C](f: Kleisli[F, A, B => C])(fa: Kleisli[F, A, B]): Kleisli[F, A, C] =
    fa.ap(f)

  override def product[B, C](fb: Kleisli[F, A, B], fc: Kleisli[F, A, C]): Kleisli[F, A, (B, C)] =
    Kleisli(a => F.product(fb.run(a), fc.run(a)))
}

private[data] trait KleisliFunctor[F[_], A] extends Functor[Kleisli[F, A, *]] {
  implicit def F: Functor[F]

  override def map[B, C](fa: Kleisli[F, A, B])(f: B => C): Kleisli[F, A, C] =
    fa.map(f)
}

private trait KleisliDistributive[F[_], R] extends Distributive[Kleisli[F, R, *]] {
  implicit def F: Distributive[F]

  override def distribute[G[_]: Functor, A, B](a: G[A])(f: A => Kleisli[F, R, B]): Kleisli[F, R, G[B]] =
    Kleisli(r => F.distribute(a)(f(_).run(r)))

  def map[A, B](fa: Kleisli[F, R, A])(f: A => B): Kleisli[F, R, B] = fa.map(f)
}

private[this] trait KleisliFunctorFilter[F[_], R] extends FunctorFilter[Kleisli[F, R, *]] {

  def FF: FunctorFilter[F]

  def functor: Functor[Kleisli[F, R, *]] = Kleisli.catsDataFunctorForKleisli(FF.functor)

  def mapFilter[A, B](fa: Kleisli[F, R, A])(f: A => Option[B]): Kleisli[F, R, B] =
    Kleisli[F, R, B] { r =>
      FF.mapFilter(fa.run(r))(f)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy