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

cats.Applicative.scala Maven / Gradle / Ivy

package cats

import simulacrum.typeclass

/**
 * Applicative functor.
 *
 * Allows application of a function in an Applicative context to a value in an Applicative context
 *
 * See: [[https://www.cs.ox.ac.uk/jeremy.gibbons/publications/iterator.pdf The Essence of the Iterator Pattern]]
 * Also: [[http://staff.city.ac.uk/~ross/papers/Applicative.pdf Applicative programming with effects]]
 *
 * Must obey the laws defined in cats.laws.ApplicativeLaws.
 */
@typeclass trait Applicative[F[_]] extends Apply[F] { self =>

  /**
   * `pure` lifts any value into the Applicative Functor.
   *
   * Applicative[Option].pure(10) = Some(10)
   */
  def pure[A](x: A): F[A]

  /**
   * `pureEval` lifts any value into the Applicative Functor.
   *
   * This variant supports optional laziness.
   */
  def pureEval[A](x: Eval[A]): F[A] = pure(x.value)

  override def map[A, B](fa: F[A])(f: A => B): F[B] = ap(fa)(pure(f))

  /**
   * Two sequentially dependent Applicatives can be composed.
   *
   * The composition of Applicatives `F` and `G`, `F[G[x]]`, is also an Applicative
   *
   * Applicative[Option].compose[List].pure(10) = Some(List(10))
   */
  def compose[G[_]](implicit GG : Applicative[G]): Applicative[λ[α => F[G[α]]]] =
    new CompositeApplicative[F,G] {
      implicit def F: Applicative[F] = self
      implicit def G: Applicative[G] = GG

    }

  def traverse[A, G[_], B](value: G[A])(f: A => F[B])(implicit G: Traverse[G]): F[G[B]] =
    G.traverse(value)(f)(this)

  def sequence[G[_]: Traverse, A](as: G[F[A]]): F[G[A]] =
    traverse(as)(a => a)

}

trait CompositeApplicative[F[_],G[_]]
    extends Applicative[λ[α => F[G[α]]]] with CompositeApply[F,G] {

  implicit def F: Applicative[F]
  implicit def G: Applicative[G]

  def pure[A](a: A): F[G[A]] = F.pure(G.pure(a))
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy