Haskell/Solutions/Applicative functors

recap
1.

2.

3.

Functions have a  instance, and it is a quite useful one. The "wrapped" value in this case is the result produced by the function. for functions is function composition.

The class
1.

2a. The choice for the first argument when there are two s is arbitrary, but matches the  implementation.

2b. and  for functions are the K and S combinators of SKI combinator calculus respectively.

Déja vu
1.

2.

Sequencing of effects
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   and so forth. However, the plumbing in  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  is not commutative. After all, the whole point of  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  is not commutative.

For the sake of completeness, here is the full deduction through the  instance, done in mostly point-free style. To protect our sanity, we will leave out the  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,   builds functorial context from the values in. The newly generated context is then combined with the preexisting context of, 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. and  are implemented using , and so they also sequence effects from left to right. That means  instances must follow suit if they are to be coherent with   ones, and at that point it becomes sensible to extend the convention to all applicative functors (even those without   instances) to minimise a source of confusion.

A sliding scale of power
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.

2a. The context of  (i.e., the tree's shape) is fully determined by the context of , and the values have no influence over the resulting context. That calls for. In the case of,   has the same shape as  , except with each leaf replaced by a tree with the shape of. Hence, the desired shape for  can be obtained by applying a tree of shape   to. In the above definition that uses, some processing is needed to get   as the first argument to  ; the definition that uses   is more natural. 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  is not an option. is not enough as well. There are no values in the  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  we might use an explicitly recursive function to tag the nodes, and then use the tags to prune the tree through the   interface. It would be unnecessary trouble, of course, but it might make a nice extra exercise.)

2c. replaces the leaves of  with   and. This  instance is very similar to the standard "combinatorial"   of lists. As the structure of the result tree depends only of the structure of  (and not of any values),   is clearly unnecessary.

alternatively, one can get away with using just  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, 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  s). By the way,  would have the exact same implementation of , only using the other instance.

The monoidal presentation
1.

2. That is a beautiful presentation of the commutativity condition. An applicative functor is commutative if the only difference between  and   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.