-The question came up in class of when box types might fail to be Mappable, or Mappables might fail to be MapNables, or MapNables might fail to be Monads.
-
-For the first failure, we noted that it's easy to define a `map` operation for the box type `R -> α`, for a fixed type `R`. You `map` a function of type `P -> Q` over a value of the boxed type <code><u>P</u></code>, that is `R -> P`, by just returning a function that takes some `R` as input, first supplies it to your `R -> P` value, and then supplies the result to your `map`ped function of type `P -> Q`. (We will be working with this Mappable extensively; in fact it's not just a Mappable but more specifically a Monad.)
-
-But if on the other hand, your box type is `α -> R`, you'll find that there is no way to define a `map` operation that takes arbitrary functions of type `P -> Q` and values of the boxed type <code><u>P</u></code>, that is `P -> R`, and returns values of the boxed type <code><u>Q</u></code>.
-
-For the second failure, that is cases of Mappables that are not MapNables, we cited box types like `(R, α)`, for arbitrary fixed types `R`. The `map` operation for these is defined by `map f (r,a) = (r, f a)`. For certain choices of `R` these can be MapNables too. The easiest case is when `R` is the type of `()`. But when we look at the MapNable Laws, we'll see that they impose constraints we cannot satisfy for *every* choice of the fixed type `R`. Here's why. We'll need to define `mid a = (r0, a)` for some specific `r0` of type `R`. Then the MapNable Laws will entail:
-
- 1. (r0,id) m$ (r,x) == (r,x)
- 2. (r0,f x) == (r0,f) m$ (r0,x)
- 3. (r0,(○)) m$ (r'',f) m$ (r',g) m$ (r,x) == (r'',f) m$ ((r',g) m$ (r,x))
- 4. (r'',f) m$ (r0,x) == (r0,($x)) m$ (r'',f)
- 5. (r0,f) m$ (r,x) == (r,($x)) m$ (r0,f)
-
-Now we are not going to be able to write a `m$` function that inspects the second element of its left-hand operand to check if it's the `id` function; the identity of functions is not decidable. So the only way to satisfy Law 1 will be to use the first element of the right-hand operand (`r`) at least in those cases when the first element of the left-hand operand is `r0`. But then that means that the result of the lhs of Law 5 will also have a first element of `r`; so, turning now to the rhs of Law 5, we see that `m$` must use the first element of its _left_-hand operand (here again `r`) at least in those cases when the first element of its right-hand operand is `r0`. If our `R` type has a natural *monoid* structure, we could just let `r0` be the monoid's identity, and have `m$` combine other `R`s using the monoid's operation. Alternatively, if the `R` type is one that we can safely apply the predicate `(r0==)` to, then we could define `m$` something like this:
-
- let (m$) (r1,f) (r2,x) = ((if r0==r1 then r2 else if r0==r2 then r1 else ...), ...)
+Sticking with the "crossing" strategy, here's how to motivate our implementation of `<=<`. Recall that we have on the one hand, an operation `filter` for lists, that applies a predicate to each element of the list, and returns a list containing only those elements which satisfied the predicate. But the elements it does retain, it retains unaltered. On the other hand, we have the operation `map` for lists, that is capable of _changing_ the list elements in the result. But it doesn't have the power to throw list elements away; elements in the source map one-to-one to elements in the result. In many cases, we want something in between `filter` and `map`. We want to be able to ignore or discard some list elements, and possibly also to change the list elements we keep. One way of doing this is to have a function `optmap`, defined like this: