Superclass defaults
Victor Nazarov
asviraspossible at gmail.com
Tue Aug 30 09:26:54 CEST 2011
I was thinking about the design of superclass default instances. I
think that we can get relatively far using the following extensions
together:
1) Multiple instance declarations
instance (Functor[a], Monad [a])
where
fmap = map
(>>=) = flip concatMap
return = (:[])
-- Declaration above is syntactic sugar for 2 declarations:
-- instance Functor[a]
-- where
-- fmap = map
-- instance Monad [a]
-- where
-- (>>=) = flip concatMap
-- return = (:[])
2) Context synonyms
-- (MonadAndFunctor a) is synonym for (Functor a, Monad a)
context (Functor a, Monad a) => MonadAndFunctor a
-- Using synonims with multiple class declarations we can define instances like
instance MonadAndFunctor [a]
where
fmap = map
(>>=) = flip concatMap
return = (:[])
-- Declaration above is syntactic sugar for
-- instance (Functor[a], Monad [a])
-- where
-- fmap = map
-- (>>=) = flip concatMap
-- return = (:[])
3) And finally Default superclass instances
Class contains default instances for superclasses:
class Functor m => Monad m
where
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a
-- default superclass instance:
instance Functor m
where
fmap f m = m >>= (return . f)
Default superclass implementations are used only when multiple
instance declarations are used:
-- no default superclass instance is used. Error is emitted when there
is no Functor instance
instance Monad [a]
where
...
-- default superclass instance is used:
instance Functor [a], Monad [a]
where
(>>=) = ...
return = ...
-- functor instance is generated automatically
-- fmap = ...
Suppose that we make Functor to be Monad's superclass.
Combination of this three extensions allows us to define compatibility modules:
module Control.Monad.Compat (Monad) where
import qualified Control.Monad (Monad(..), Functor(..)) as CM
context CM.Functor m, CM.Monad m => Monad m
When we have compilation failure in client code after our Monad
definition change: "No Functor instance found for Foo":
instance Monad Foo
where ...
, we simply add following two lines to the module:
import Prelude hiding (Monad)
import Control.Monad.Compat (Monad)
and compilation succeeds.
Pros:
Client code can remain Haskell 98/2010 and doesn't require any extensions.
Three extensions seems simple when separate (I think there are many
corner cases)
Cons:
Intervention is required into client code (But I think it is required anyway).
--
Victor Nazarov
More information about the Glasgow-haskell-users
mailing list