Inline the definition of 'ap' in the Monad laws
authorChris Martin <ch.martin@gmail.com>
Wed, 27 Mar 2019 20:23:57 +0000 (14:23 -0600)
committerMarge Bot <ben+marge-bot@smart-cactus.org>
Wed, 3 Apr 2019 04:41:05 +0000 (00:41 -0400)
The law as it is currently written is meaningless, because nowhere have
we defined the implementation of 'ap'. The reader of the Control.Monad
documentation is provided with only a type signature,

> ap :: Monad m => m (a -> b) -> m a -> m b

an informal description,

> In many situations, the liftM operations can be replaced by uses of
> ap, which promotes function application.

and a relationship between 'ap' and the 'liftM' functions

> return f `ap` x1 `ap` ... `ap` xn
> is equivalent to
> liftMn f x1 x2 ... xn

Without knowing how 'ap' is defined, a law involving 'ap' cannot
provide any guidance for how to write a lawful Monad instance, nor can
we conclude anything from the law.

I suspect that a reader equipped with the understanding that 'ap' was
defined prior to the invention of the Applicative class could deduce
that 'ap' must be defined in terms of (>>=), but nowhere as far as I can
tell have we written this down explicitly for readers without the
benefit of historical context.

If the law is meant to express a relationship among (<*>), (>>=), and
'return', it seems that it is better off making this statement directly,
sidestepping 'ap' altogether.

libraries/base/GHC/Base.hs

index cf9fd81..a992368 100644 (file)
@@ -519,7 +519,7 @@ class  Functor f  where
 --
 --   * @'pure' = 'return'@
 --
---   * @('<*>') = 'ap'@
+--   * @m1 '<*>' m2 = m1 '>>=' (\x1 -> m2 '>>=' (\x2 -> 'return' (x1 x2)))@
 --
 --   * @('*>') = ('>>')@
 --
@@ -639,7 +639,7 @@ Instances of 'Monad' should satisfy the following:
 Furthermore, the 'Monad' and 'Applicative' operations should relate as follows:
 
 * @'pure' = 'return'@
-* @('<*>') = 'ap'@
+* @m1 '<*>' m2 = m1 '>>=' (\x1 -> m2 '>>=' (\x2 -> 'return' (x1 x2)))@
 
 The above laws imply: