Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the pros and cons of adding additional functions/combinators to a typeclass definition?

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
like image 957
Matt Fenwick Avatar asked Sep 20 '12 15:09

Matt Fenwick


3 Answers

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.

like image 183
C. A. McCann Avatar answered Nov 10 '22 23:11

C. A. McCann


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.

like image 3
Fred Foo Avatar answered Nov 10 '22 22:11

Fred Foo


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.`

like image 3
Jeremy Gibbons Avatar answered Nov 10 '22 23:11

Jeremy Gibbons