ap
doesn\'t have a documented spec, and reads with a comment pointing out it could be <*>
, but isn\'t for practical reasons:
So I assume the
ap
in the(<*>) = ap
law is shorthand for "right-hand side ofap
" and the law actually expresses a relationship between>>=
,return
and<*>
right?It seems to me
(<*>) = ap
doesn't strictly imply anything (at least post-AMP). Presumably it's trying to express some relationship between<*>
and the right-hand side ofap
. Maybe I'm being pedantic.
Speaking pedantically, I'd say the opposite: because ap
is definitionally equal to its right-hand side, saying (<*>) = ap
is exactly the same as saying m1 <*> m2 = do { x1 <- m1; x2 <- m2; return (x1 x2) }
. It's just the normal first step of dealing with equalities like that: expanding the definitions.
Reply to the comment:
Right, but the definition is free to change.
Then the law would change or be removed too. Just as when/if join
is added to Monad
the current definition will become a law instead.
it wouldn't have been possible to define it literally as
ap = <*>
Do you mean it would be impossible to define ap
or the law in this way?
If ap
, then you are correct: it would have the wrong type. But stating the law like this would be fine.
Every Monad
gives rise to an Applicative
, and for that induced Applicative
, <*> = ap
will hold definitionally. But given two structures - Monad m
and Applicative m
- there is no guarantee that these structures agree without the two laws <*> = ap
and pure = return
. For example, take the 'regular' Monad
instance for lists, and the zip-list Applicative
instance. While there is nothing fundamentally 'wrong' about a Monad
and Applicative
instance disagreeing, it would probably be confusing to most users, and so it's prohibited by the Monad
laws.
tl;dr The laws in question serve to ensure that Monad
and Applicative
agree in an intuitively obvious way.