Commit 65f887e1 authored by Austin Seipp's avatar Austin Seipp

base: Add some notes about the default impl of '(>>)'

See Note [Recursive bindings for Applicative/Monad]. This documents the
tricky little details that kept me occupied for so long with this patch,
and why exactly we deviate from the original proposal.
Signed-off-by: default avatarAustin Seipp <austin@well-typed.com>
parent df2fa25a
......@@ -418,7 +418,7 @@ class Applicative m => Monad m where
-- by the first, like sequencing operators (such as the semicolon)
-- in imperative languages.
(>>) :: forall a b. m a -> m b -> m b
m >> k = m >>= \_ -> k
m >> k = m >>= \_ -> k -- See Note [Recursive bindings for Applicative/Monad]
{-# INLINE (>>) #-}
-- | Inject a value into the monadic type.
......@@ -430,6 +430,28 @@ class Applicative m => Monad m where
fail :: String -> m a
fail s = error s
{- Note [Recursive bindings for Applicative/Monad]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The original Applicative/Monad proposal stated that after
implementation, the designated implementation of (>>) would become
(>>) :: forall a b. m a -> m b -> m b
(>>) = (*>)
by default. You might be inclined to change this to reflect the stated
proposal, but you really shouldn't! Why? Because people tend to define
such instances the /other/ way around: in particular, it is perfectly
legitimate to define an instance of Applicative (*>) in terms of (>>),
which would lead to an infinite loop for the default implementation of
Monad! And people do this in the wild.
This turned into a nasty bug that was tricky to track down, and rather
than eliminate it everywhere upstream, it's easier to just retain the
original default.
-}
-- | Promote a function to a monad.
liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r
liftM f m1 = do { x1 <- m1; return (f x1) }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment