# Haskell/Solutions/Applicative functors

← Back to Applicative functors

## Functor recap

* Exercises
* Define instances of Functor for the following types:
* A rose tree, defined as: data Tree a = Node a [Tree a]
* Either e for a fixed e.
* The function type ((->) r). In this case, f a will be (r -> a)
1.
2.
3.
Functions have a Functor instance, and it is a quite useful one. The "wrapped" value in this case is the result produced by the function.
fmap for functions is function composition.

## The Applicative class

* Exercises
* Check that the Applicative laws hold for this instance for Maybe
* Write Applicative instances for a. Either e, for a fixed e b. ((->) r), for a fixed t
1.
2a.
The choice for the first argument when there are two Lefts is arbitrary, but matches the Data.Either implementation.
2b.
pure and (<*>) for functions are the K and S combinators of w:SKI combinator calculus respectively.

## Déja vu

* Exercises
* Write a definition of (<*>) using (>>=) and fmap. Do not use do-notation.
* Implement liftA5 :: Applicative f => (a -> b -> c -> d -> e -> k) -> f a -> f b -> f c -> f d -> f e -> f k
1.
2.

## Sequencing of effects

* Exercises
* For the list functor, implement from scratch (that is, without using anything from Applicative or Monad directly) both (<*>) and its version with the "wrong" sequencing of effects, (<|*|>) :: Applicative f => f (a -> b) -> f a -> f b
* Rewrite the definition of commutativity for a Monad, using do-notation instead of ap or liftM2.
* Are the following applicative functors commutative? a. ZipList b. ((->) r) c. State s (Use the newtype definition from the State chapter. Hint: You may find the answer to exercise 2 of this block useful.)
* What is the result of [2,7,8] *> [3,9]? (Try to guess without writing.)
* Implement (<**>) in terms of other Applicative functions.
* As we have just seen, some functors allow two legal implementations of (<*>) which are only different in the sequencing of effects. Why there is not an analogous issue involving (>>=)?
1.
Note how the (<*>) implementation matches exactly the general (<*>)-from-(>>=) implementation in the first exercise of the "Déja vu" section.
2.
Another pedantically slow derivation follows.
3a.
3b.
3c.
Two observations. Firstly, we might continue the solution by writing the binds explicitly, substituting the definitions of (>>=) and return and so forth. However, the plumbing in State is quite convoluted, making the full derivation rather mind-numbing. For that reason, we will continue, at first, in a less formal way, so that the key insights are not obscured. Secondly, we have very good reasons to suspect State is not commutative. After all, the whole point of State is threading state updates with computations which depend on that state, and there is no particular reason why the order of the state transitions shouldn't matter. Following that lead, we will, instead of attempting to prove the do-blocks are equivalent, look for a counter-example.
We will now perform the substitutions, while keeping track of the (result, state) pairs in each step.
Neither the final states nor the final results match. That is enough to show State s is not commutative.
For the sake of completeness, here is the full deduction through the Applicative instance, done in mostly point-free style. To protect our sanity, we will leave out the newtype wrapping and unwrapping.
4.
The skeleton of the second list is distributed into the skeleton of the first list; the values in the first list are discarded.
5.
6.
Because (>>=) imposes left-to-right sequencing. In m >>= k, k builds functorial context from the values in m. The newly generated context is then combined with the preexisting context of m, which is the matrix for creating the context of the result.
Incidentally, the fact (>>=) performing left-to-right sequencing is the main reason for the convention that leads applicative operators to do the same. liftM2 and ap are implemented using (>>=), and so they also sequence effects from left to right. That means Applicative instances must follow suit if they are to be coherent with Monad ones, and at that point it becomes sensible to extend the convention to all applicative functors (even those without Monad instances) to minimise a source of confusion.

## A sliding scale of power

* Exercises
* The next few exercises concern the following tree data structure: data AT a = L a | B (AT a) (AT a)
* Write Functor, Applicative and Monad instances for AT. Do not use shortcuts such as pure = return. The Applicative and Monad instances should match; in particular, (<*>) should be equivalent to ap, which follows from the Monad instance.
* Implement the following functions, using either the Applicative instance, the Monad one or neither of them, if neither is enough to provide a solution. Between Applicative and Monad, choose the least powerful one which is still good enough for the task. Justify your choice for each case in a few words. a. fructify :: AT a -> AT a, which grows the tree by replacing each leaf L with a branch B containing two copies of the leaf. b. prune :: a -> (a -> Bool) -> AT a -> AT a, with prune z p t replacing a branch of t with a leaf carrying the default value z whenever any of the leaves directly on it satisfies the test p. c. reproduce :: (a -> b) -> (a -> b) -> AT a -> AT b, with reproduce f g t resulting in a new tree with two modified copies of t on the root branch. The left copy is obtained by applying f to the values in t, and the same goes for g and the right copy.
* There is another legal instance of Applicative for AT (the reversed sequencing version of the original one doesn't count). Write it. Hint: this other instance can be used to implement sagittalMap :: (a -> b) -> (a -> b) -> AT a -> AT b which, when given a branch, maps one function over the left child tree and the other over the right child tree.
* (In case you are wondering, "AT" stands for "apple tree". Botanist readers, please forgive the weak metaphors.)
1.
A definition ready to be loaded in GHCi:
Note how the laws of the various classes can guide you towards the correct instances. For example, the two first cases in the definition of (<*>) follow immediately from the fmap and interchange laws of Applicative.
2a.
The context of fructify t (i.e., the tree's shape) is fully determined by the context of t, and the values have no influence over the resulting context. That calls for Applicative. In the case of AT, tf <*> tx has the same shape as tf, except with each leaf replaced by a tree with the shape of tx. Hence, the desired shape for fructify t can be obtained by applying a tree of shape B (L _) (L _) to t. In the above definition that uses (<*>), some processing is needed to get t as the first argument to (<*>); the definition that uses (<**>) is more natural. id is used as each morphism function to produce the same value in each new leaf as that of the parent leaf.
2b.
For a second time we need to change the tree structure depending on its values, so Applicative is not an option. Monad is not enough as well. There are no values in the B nodes for the second argument of (>>=) to generate context from, and there is no way to access values elsewhere in the tree while performing the monadic bind. Thus we have resorted to a plain old explicitly recursive function.
(Note that if there were values in B we might use an explicitly recursive function to tag the nodes, and then use the tags to prune the tree through the Monad interface. It would be unnecessary trouble, of course, but it might make a nice extra exercise.)
2c.
reproduce replaces the leaves of B (L f) (L g) with fmap f t and fmap g t. This Applicative instance is very similar to the standard "combinatorial" Applicative of lists. As the structure of the result tree depends only of the structure of t (and not of any values), Monad is clearly unnecessary.
alternatively, one can get away with using just Functor as follows
3.
The alternative instance is:
It only combines subtrees with matching positions in the tree structures. The resulting behaviour is similar to that of ZipLists, except that when the subtree shapes are different it inserts missing branches rather than removing extra ones (and it couldn't be otherwise, since there are no empty ATs). By the way, sagittalMap would have the exact same implementation of reproduce, only using the other instance.

## The monoidal presentation

* Exercises
* Write implementations for unit and (*&*) in terms of pure and (<*>), and vice-versa.
* Formulate the law of commutative applicative functors (see the Sequencing of effects section) in terms of the Monoidal methods.
* Write from scratch Monoidal instances for: a. ZipList b. ((->) r)
1.
2.
That is a beautiful presentation of the commutativity condition. An applicative functor is commutative if the only difference between u *&* v and v *&* u is the elements of the pairs within them being swapped. All else - the values of the elements and the context around them - must be the same.
3a.
3b.