Looking at the source for Monad:
class Monad m where
(>>=) :: forall a b. m a -> (a -> m b) -> m b
(>>) :: forall a b. m a -> m b -> m b
return :: a -> m a
fail :: String -> m a
{-# INLINE (>>) #-}
m >> k = m >>= \_ -> k -- <-- !! right here !!
fail s = error s
You can see that >>
has a default implementation. My question is, is it considered good or bad practice, and why, to include a function/combinator in the typeclass, instead of providing it separately outside of the typeclass?
That is, why not:
class Monad m where
(>>=) :: forall a b. m a -> (a -> m b) -> m b
return :: a -> m a
fail :: String -> m a
fail s = error s
and somewhere else:
(>>) :: forall a b. m a -> m b -> m b
{-# INLINE (>>) #-}
m >> k = m >>= \_ -> k
As far as I know, there are two main reasons to include "extra" functions:
Efficiency: Sometimes an inefficient generic implementation exists, and the class's author expects instance-specific implementations to be significantly better. In such cases, including the function in the class with a default implementation means that instances can use optimized versions if they want, but aren't required to. For a fun example of this, look at Foldable
. This is also true of Monad
.
Choice of implementation: Often there are several subsets of the class functions that could be used; including all the potential functions and using default implementations in terms of each other means that an instance can pick some functions to implement and get the rest automatically. This also applies to Foldable
, but Eq
is a simpler example.
This way, custom >>
can be implemented for monads where it can be done more efficiently or naturally than via m >>= \_ -> k
, but a default implementation still exists.
Another argument for including methods in the typeclass is when they should satisfy certain laws, or when they make the statement of those laws clearer. I would argue that the laws ought morally to be associated with the typeclass ("what must I provide in order to declare an instance of this class?") For example, you might prefer to state the monad laws in terms of return
, join
and fmap
, rather than return
and >>=
; that encourages you to put all four operators in the type class (and make Monad
a subclass of Functor
!), and give default definitions of >>=
in terms of join
and vice versa.`
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With