tricky instance declarations

Alastair Reid reid@cs.utah.edu
03 May 2002 13:02:04 +0100


Warrick Gray <oinutter@hotmail.com> writes:
> data ConnError = ...
> 
> -- error propagating monad:
> instance Monad (Either ConnError) where

> -- combined IO & error propagating monads
> instance Monad (IO (Either ConnError a)) where

> I know the first declaration works with GHC compiler flag
> "-fglasgow-exts", but something about the line "Monad (IO (Either
> ConnError a))" makes me (and the compiler) very nervous.  How should I
> be expressing this?

You're probably seeing problems because Monad is a constructor class
(i.e., expects an argument of kind * -> *) not a type class (which
would expect an argument of kind *).  You used Monad correctly in the
first instance declaration (i.e., there's no mention of 'a') but not
in the second (you did mention the 'a').

Unfortunately, the fix is slightly awkward.  What you want to write is
something like:

> instance Monad (IO . Either ConnError) where

but you can't use . to compose type constructors the way you can
compose functions so that doesn't work.  What you have to do is:

> newtype IOE a = MkIOE (IO (Either ConnError a))
> unIOE (MkIOE x) = x
> instance Monad IOE where ...

or, generalizing slightly so that you only have to go through the pain
of this once:

> newtype IOF m a = MkIOF (IO (m a))
> unIOF (MkIOF x) = x
> instance Monad (IOF (Either ConnError)) where ...


Of course, the easiest fix is to use the fact that the IO monad has
error propagation built into it.  If you can encode your errors as
strings, you're all set (or you could use the GHC Dynamic extensions
if non-portability doesn't disturb).


Hope this helps,

Alastair Reid