Applicative
Whereas a functor allows application of a pure function to a value in a context, an Applicative also allows application of a function in a context to a value in a context.
Applicative
is a subclass of Apply
, which adds an identity, pure
.
Typical imports
import scalaz.tc._
import scalaz.Predef._
import scalaz.Scalaz._
Instance declaration
scala> case class ZipList[A](val value: List[A]) extends AnyVal
defined class ZipList
scala> /* Note that this is _not_ the Applicative instance for List! */
| implicit val zipListAp: Applicative[ZipList] = instanceOf(new ApplicativeClass[ZipList] {
| override def pure[A](a: A): ZipList[A] = ZipList(List(a))
|
| override def ap[A, B](fa: ZipList[A])(f: ZipList[A => B]): ZipList[B] =
| ZipList((fa.value zip f.value).map(t => t._2(t._1)))
|
| override def map[A, B](fa: ZipList[A])(f: A => B): ZipList[B] =
| ZipList(fa.value map f)
| })
zipListAp: scalaz.tc.Applicative[ZipList] = $anon$1@58a1066d
Usage
scala> val l: ZipList[Int] = 123.pure[ZipList]
l: ZipList[scalaz.Predef.Int] = ZipList(List(123))
scala> l.map(_ + 25)
res1: ZipList[Int] = ZipList(List(148))
scala> val l2 = ZipList(List(17, 19, 23))
l2: ZipList[Int] = ZipList(List(17, 19, 23))
scala> val fs: ZipList[Int => Int] = ZipList(List(_ * 2, _ * 3, _ * 4, _ * 5))
fs: ZipList[scalaz.Predef.Int => scalaz.Predef.Int] = ZipList(List($$Lambda$10728/1620553481@1de594e1, $$Lambda$10729/1177918422@77e447a0, $$Lambda$10730/590664621@72c85b4a, $$Lambda$10731/1087869973@e430e3a))
scala> l2.ap(fs)
res2: ZipList[scalaz.Predef.Int] = ZipList(List(34, 57, 92))
Law
The only law introduced by Applicative
in addition to Apply
’s laws is:
scala> def applyIdentity[F[_], A, T](in: F[A])(assert: (F[A], F[A]) => T)(implicit F: Applicative[F]) =
| assert(in, F.ap(in)(F.pure((a: A) => a)))
applyIdentity: [F[_], A, T](in: F[A])(assert: (F[A], F[A]) => T)(implicit F: scalaz.tc.Applicative[F])T
That is to say, pure(identity)
is an identity for ap
.
pure
does not “modify” the F[_]
context.
Note that a free law (derived for “free” from the type of pure
) states:
scala> def freePureMap[F[_]: Applicative, A, B, T](a: A, f: A => B)(assert: (F[B], F[B]) => T): T =
| assert(f(a).pure[F], a.pure[F].map(f))
freePureMap: [F[_], A, B, T](a: A, f: A => B)(assert: (F[B], F[B]) => T)(implicit evidence$1: scalaz.tc.Applicative[F])T
As long as no casting or isInstanceOf
is done by the implementor,
this law is guaranteed and doesn’t necessarily need to be tested.