[Haskell-cafe] AMP - how do you motivate this in teaching?
Albert Y. C. Lai
trebla at vex.net
Fri Nov 20 21:41:08 UTC 2015
On 2015-11-19 04:27 PM, Johannes Waldmann wrote:
> Now, I don't want to bring on another general discussion of AMP -
> instead I'd like to hear from people who use monads
> in teaching (e.g., to define semantic domains)
> about how they sell "Applicative m =>" to their students.
> (The intersection of AMPers and teachers is non-empty?)
(I do not teach Haskell. But I teach other things, and I explain Haskell
things in local Haskell meetups.)
I'm pretty sure we can all agree to start with Functor. This gives us
fmap so we can apply a 1-ary function to 1 action.
But we are greedy, we also want to apply a 2-ary function to 2 actions.
Functor alone can't do this. We need at least liftA2. And then we wonder
about 3-ary, 4-ary...
It turns out that pure and (<*>) cover them all. To apply a 5-ary
function to 5 actions, we can write the very regular
pure f <*> as <*> bs <*> cs <*> ds <*> es
(Given lambda calculus and Functor, the following suites have equivalent
ability, so each suite could define Applicative: {pure, liftA2}, {pure,
liftA2 (,)}, {pure, (<*>)}.)
It also turns out that you can already write sequenceA (you didn't use
all of Monad to get sequence) and traverse (you didn't use all of Monad
to get mapM).
So this is how I would motivate Applicative given Functor. I received
the gift of 1-ary application, but then I get greedy and want n-ary
application and the silver axe and the golden axe...
The final transition, from Applicative to Monad, is driven by a whole
new level of greed. I received the gift of n-ary application and a
silver axe and a golden axe; now I want a smart axe. Here is what I mean:
In the compound action
fs <*> xs
the sub-action fs cannot behave dependently on what "return value" the
sub-action xs "returns". (Likewise for the other way round.) That data
dependency is provided by Monad's (>>=) or (=<<). One operand can now
peak at the "return value" of the other sub-action, and do some
Turing-smart processing, before it decides what action to take.
This is my version of what other people call successively expanding API.
More information about the Haskell-Cafe
mailing list