trait Applicative[F[_]] extends Functor[F] {
def pure[A](a: A): F[A]
def ap[A, B](f: F[A => B])(fa: F[A]): F[B]
def map[A, B](fa: F[A])(f: A => B): F[B] =
ap(pure(f))(fa)
}
object Applicative {
import Functor._
implicit class ApplicativeOps[A, B, F[_]: Applicative](f: F[A => B]) {
def <*>(fa: F[A]): F[B] =
[Applicative[F]].ap(f)(fa)
implicitly}
implicit class FnCofunctor[A, B](g: A => B) {
def <%>[F[_]: Functor](x: F[A]) = x map g
}
}
From Wikibooks:
pure id <*> v = v -- Identity
pure f <*> pure x = pure (f x) -- Homomorphism
u <*> pure y = pure ($ y) <*> u -- Interchange
pure (.) <*> u <*> v <*> w = u <*> (v <*> w) -- Composition