@@ -6,45 +6,277 @@ source: "core/src/main/scala/cats/Applicative.scala"
66scaladoc : " #cats.Applicative"
77---
88# Applicative
9+ ` Applicative ` extends [ ` Functor ` ] ( functor.html ) with an ` ap ` and ` pure ` method.
910
10- ` Applicative ` extends [ ` Apply ` ] ( apply.html ) by adding a single method,
11- ` pure ` :
11+ ``` tut:book:silent
12+ import cats.Functor
1213
13- ``` scala
14- def pure [A ](x : A ): F [A ]
15- ````
14+ trait Applicative[F[_]] extends Functor[F] {
15+ def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
16+
17+ def pure[A](a: A): F[A]
18+
19+ def map[A, B](fa: F[A])(f: A => B): F[B] = ap(pure(f))(fa)
20+ }
21+ ```
22+
23+ ` pure ` wraps the value into the type constructor - for ` Option ` this could be ` Some(_) ` , for ` Future `
24+ ` Future.successful ` , and for ` List ` a singleton list.
25+
26+ ` ap ` is a bit tricky to explain and motivate, so we'll look at an alternative but equivalent
27+ formulation via ` product ` .
28+
29+ ``` tut:book:silent
30+ trait Applicative[F[_]] extends Functor[F] {
31+ def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
32+
33+ def pure[A](a: A): F[A]
34+ }
35+
36+ // Example implementation for right-biased Either
37+ implicit def applicativeForEither[L]: Applicative[Either[L, ?]] = new Applicative[Either[L, ?]] {
38+ def product[A, B](fa: Either[L, A], fb: Either[L, B]): Either[L, (A, B)] = (fa, fb) match {
39+ case (Right(a), Right(b)) => Right((a, b))
40+ case (Left(l) , _ ) => Left(l)
41+ case (_ , Left(l) ) => Left(l)
42+ }
43+
44+ def pure[A](a: A): Either[L, A] = Right(a)
45+
46+ def map[A, B](fa: Either[L, A])(f: A => B): Either[L, B] = fa match {
47+ case Right(a) => Right(f(a))
48+ case Left(l) => Left(l)
49+ }
50+ }
51+ ```
52+
53+ Note that in this formulation ` map ` is left abstract, whereas in the previous one with ` ap ` ` map `
54+ could be implemented in terms of ` ap ` and ` pure ` . This suggests that ` ap ` is equivalent to
55+ ` map ` and ` product ` , which is indeed the case.
56+
57+ Such an ` Applicative ` must obey three laws:
58+
59+ * Associativity: No matter the order in which you product together three values, the result is isomorphic
60+ * ` fa.product(fb).product(fc) ~ fa.product(fb.product(fc)) `
61+ * With ` map ` , this can be made into an equality with ` fa.product(fb).product(fc) = fa.product(fb.product(fc)).map { case (a, (b, c)) => ((a, b), c) } `
62+ * Left identity: Zipping a value on the left with unit results in something isomorphic to the original value
63+ * ` pure(()).product(fa) ~ fa `
64+ * As an equality: ` pure(()).product(fa).map(_._2) = fa `
65+ * Right identity: Zipping a value on the right with unit results in something isomorphic to the original value
66+ * ` fa.product(pure(())) ~ fa `
67+ * As an equality: ` fa.product(pure(())).map(_._1) = fa `
68+
69+ ## Applicatives for effect management
70+
71+ If we view ` Functor ` as the ability to work with a single effect, ` Applicative ` encodes working with
72+ multiple ** independent** effects. Between ` product ` and ` map ` , we can take two separate effectful values
73+ and compose them. From there we can generalize to working with any N number of independent effects.
74+
75+ ``` tut:reset:book:silent
76+ import cats.Applicative
77+
78+ def product3[F[_]: Applicative, A, B, C](fa: F[A], fb: F[B], fc: F[C]): F[(A, B, C)] = {
79+ val F = Applicative[F]
80+ val fabc = F.product(F.product(fa, fb), fc)
81+ F.map(fabc) { case ((a, b), c) => (a, b, c) }
82+ }
83+ ```
84+
85+ ## What is ap?
86+
87+ Let's see what happens if we try to compose two effectful values with just ` map ` .
88+
89+ ``` tut:book:silent
90+ import cats.instances.option._
91+
92+ val f: (Int, Char) => Double = (i, c) => (i + c).toDouble
93+
94+ val int: Option[Int] = Some(5)
95+ val char: Option[Char] = Some('a')
96+ ```
97+
98+ ``` tut:book
99+ int.map(i => (c: Char) => f(i, c)) // what now?
100+ ```
101+
102+ We have an ` Option[Char => Double] ` and an ` Option[Double] ` to which we want to apply the function to,
103+ but ` map ` doesn't give us enough power to do that. Hence, ` ap ` .
104+
105+ ## Applicatives compose
106+
107+ Like [ ` Functor ` ] ( functor.html ) , ` Applicative ` s compose. If ` F ` and ` G ` have ` Applicative ` instances, then so
108+ does ` F[G[_]] ` .
109+
110+ ``` tut:book:silent
111+ import cats.data.Nested
112+ import cats.instances.future._
113+ import scala.concurrent.Future
114+ import scala.concurrent.ExecutionContext.Implicits.global
115+
116+ val x: Future[Option[Int]] = Future.successful(Some(5))
117+ val y: Future[Option[Char]] = Future.successful(Some('a'))
118+ ```
119+
120+ ``` tut:book
121+ val composed = Applicative[Future].compose[Option].map2(x, y)(_ + _)
122+
123+ val nested = Applicative[Nested[Future, Option, ?]].map2(Nested(x), Nested(y))(_ + _)
124+ ```
125+
126+ ## Traverse
127+
128+ The straightforward way to use ` product ` and ` map ` (or just ` ap ` ) is to compose ` n ` independent effects,
129+ where ` n ` is a fixed number. In fact there are convenience methods named ` apN ` , ` mapN ` , and ` tupleN ` (replacing
130+ ` N ` with a number 2 - 22) to make it even easier.
131+
132+ Imagine we have one ` Option ` representing a username, one representing a password, and another representing
133+ a URL for logging into a database.
134+
135+ ``` tut:book:silent
136+ import java.sql.Connection
137+
138+ val username: Option[String] = Some("username")
139+ val password: Option[String] = Some("password")
140+ val url: Option[String] = Some("some.login.url.here")
141+
142+ // Stub for demonstration purposes
143+ def attemptConnect(username: String, password: String, url: String): Option[Connection] = None
144+ ```
16145
17- This method takes any value and returns the value in the context of
18- the functor. For many familiar functors, how to do this is
19- obvious. For `Option`, the `pure` operation wraps the value in
20- `Some`. For `List`, the `pure` operation returns a single element
21- `List`:
146+ We know statically we have 3 ` Option ` s, so we can use ` map3 ` specifically.
22147
23148``` tut:book
24- import cats ._
149+ Applicative[Option].map3(username, password, url)(attemptConnect)
150+ ```
151+
152+ Sometimes we don't know how many effects will be in play - perhaps we are receiving a list from user
153+ input or getting rows from a database. This implies the need for a function:
154+
155+ ``` tut:book:silent
156+ def sequenceOption[A](fa: List[Option[A]]): Option[List[A]] = ???
157+
158+ // Alternatively..
159+ def traverseOption[A, B](as: List[A])(f: A => Option[B]): Option[List[B]] = ???
160+ ```
161+
162+ Users of the standard library ` Future.sequence ` or ` Future.traverse ` will find these names and signatures
163+ familiar.
164+
165+ Let's implement ` traverseOption ` (you can implement ` sequenceOption ` in terms of ` traverseOption ` ).
166+
167+ ``` tut:book:silent
168+ def traverseOption[A, B](as: List[A])(f: A => Option[B]): Option[List[B]] =
169+ as.foldRight(Some(List.empty[B]): Option[List[B]]) { (a: A, acc: Option[List[B]]) =>
170+ val optB: Option[B] = f(a)
171+ // optB and acc are independent effects so we can use Applicative to compose
172+ Applicative[Option].map2(optB, acc)(_ :: _)
173+ }
174+ ```
175+
176+ ``` tut:book
177+ traverseOption(List(1, 2, 3))(i => Some(i): Option[Int])
178+ ```
179+
180+ This works...but if we look carefully at the implementation there's nothing ` Option ` -specific going on. As
181+ another example let's implement the same function but for ` Either ` .
182+
183+ ``` tut:book:silent
184+ import cats.instances.either._
185+
186+ def traverseEither[E, A, B](as: List[A])(f: A => Either[E, B]): Either[E, List[B]] =
187+ as.foldRight(Right(List.empty[B]): Either[E, List[B]]) { (a: A, acc: Either[E, List[B]]) =>
188+ val eitherB: Either[E, B] = f(a)
189+ Applicative[Either[E, ?]].map2(eitherB, acc)(_ :: _)
190+ }
191+ ```
192+
193+ ``` tut:book
194+ traverseEither(List(1, 2, 3))(i => if (i % 2 != 0) Left(s"${i} is not even") else Right(i / 2))
195+ ```
196+
197+ The implementation of ` traverseOption ` and ` traverseEither ` are more or less identical, modulo the initial
198+ "accumulator" to ` foldRight ` . But even that could be made the same by delegating to ` Applicative#pure ` !
199+ Generalizing ` Option ` and ` Either ` to any ` F[_]: Applicative ` gives us the fully polymorphic version.
200+ Existing data types with ` Applicative ` instances (` Future ` , ` Option ` , ` Either[E, ?] ` , ` Try ` ) can call it by fixing ` F `
201+ appropriately, and new data types need only be concerned with implementing ` Applicative ` to do so as well.
202+
203+ ``` tut:book:silent
204+ def traverse[F[_]: Applicative, A, B](as: List[A])(f: A => F[B]): F[List[B]] =
205+ as.foldRight(Applicative[F].pure(List.empty[B])) { (a: A, acc: F[List[B]]) =>
206+ val fb: F[B] = f(a)
207+ Applicative[F].map2(fb, acc)(_ :: _)
208+ }
209+ ```
210+
211+ This function is provided by Cats via the ` Traverse[List] ` instance and syntax, which is covered in another
212+ tutorial.
213+
214+ ``` tut:book:silent
215+ import cats.instances.list._
216+ import cats.syntax.traverse._
217+ ```
218+
219+ ``` tut:book
220+ List(1, 2, 3).traverse(i => Some(i): Option[Int])
221+ ```
222+
223+ With this addition of ` traverse ` , we can now compose any number of independent effects, statically known or otherwise.
224+
225+ ## Apply - a weakened Applicative
226+ A closely related type class is ` Apply ` which is identical to ` Applicative ` , modulo the ` pure `
227+ method. Indeed in Cats ` Applicative ` is a subclass of ` Apply ` with the addition of this method.
228+
229+ ``` scala
230+ trait Apply [F [_]] extends Functor [F ] {
231+ def ap [A , B ](ff : F [A => B ])(fa : F [A ]): F [B ]
232+ }
233+
234+ trait Applicative [F [_]] extends Apply [F ] {
235+ def pure [A ](a : A ): F [A ]
236+
237+ def map [A , B ](fa : F [A ])(f : A => B ): F [B ] = ap(pure(f))(fa)
238+ }
239+ ```
240+
241+ The laws for ` Apply ` are just the laws of ` Applicative ` that don't mention ` pure ` . In the laws given
242+ above, the only law would be associativity.
243+
244+ One of the motivations for ` Apply ` 's existence is that some types have ` Apply ` instances but not
245+ ` Applicative ` - one example is ` Map[K, ?] ` . Consider the behavior of ` pure ` for ` Map[K, A] ` . Given
246+ a value of type ` A ` , we need to associate some arbitrary ` K ` to it but we have no way of doing that.
247+
248+ However, given existing ` Map[K, A] ` and ` Map[K, B] ` (or ` Map[K, A => B] ` ), it is straightforward to
249+ pair up (or apply functions to) values with the same key. Hence ` Map[K, ?] ` has an ` Apply ` instance.
250+
251+ ## Syntax
252+
253+ Syntax for ` Applicative ` (or ` Apply ` ) is available under the ` cats.implicits._ ` import. The most
254+ interesting syntax is focused on composing independent effects - there are two options for this.
255+
256+ The first is the builder syntax which incrementally builds up a collection of effects until a
257+ function is applied to compose them.
258+
259+ ``` tut:book:silent
25260import cats.implicits._
26261
27- Applicative [ Option ].pure( 1 )
28- Applicative [ List ].pure( 1 )
262+ val o1: Option[Int] = Some(42 )
263+ val o2: Option[String] = Some("hello" )
29264```
30265
31- Like [ ` Functor ` ] ( functor.html ) and [ ` Apply ` ] ( apply.html ) , ` Applicative `
32- functors also compose naturally with each other. When
33- you compose one ` Applicative ` with another, the resulting ` pure `
34- operation will lift the passed value into one context, and the result
35- into the other context:
266+ ``` tut:book
267+ (o1 |@| o2).map((i: Int, s: String) => i.toString ++ s)
268+ (o1 |@| o2).tupled
269+ ```
270+
271+ The second expects the effects in a tuple and works by enriching syntax on top of the existing
272+ ` TupleN ` types.
36273
37274``` tut:book
38- import cats.data.Nested
39- val nested = Applicative[Nested[List, Option, ?]].pure(1)
40- val unwrapped = nested.value
275+ (o1, o2).map2((i: Int, s: String) => i.toString ++ s)
41276```
42277
43- ## Applicative Functors & Monads
278+ ## Further Reading
44279
45- ` Applicative ` is a generalization of [ ` Monad ` ] ( monad.html ) , allowing expression
46- of effectful computations in a pure functional way.
280+ * [ Applicative Programming with Effects] [ applicativePaper ] - McBride, Patterson. JFP 2008.
47281
48- ` Applicative ` is generally preferred to ` Monad ` when the structure of a
49- computation is fixed a priori. That makes it possible to perform certain
50- kinds of static analysis on applicative values.
282+ [ applicativePaper ] : http://www.staff.city.ac.uk/~ross/papers/Applicative.html " Applicative Programming with Effects "
0 commit comments