the MPTC Dilemma (please solve)

Manuel M T Chakravarty chak at
Sun Mar 19 11:25:44 EST 2006

Bulat Ziganshin:
> Hello Lennart,
> Sunday, March 19, 2006, 4:05:03 AM, you wrote:
> LA> I have to agree with Manuel.  I write a lot of Haskell code.
> LA> People even pay me to do it.  I usually stay with Haskell-98,
> when i wrote application code, i also don't used extensions very much,
> i even don't used Haskell-98 very much and afair don't defined any type
> classes at all
> but when i gone to writing libraries, that can be used by everyone,
> type classes and requirement in even more extensions is what i need
> permanently. in particular, i try to write library so what any
> conception (stream, Binary, reference, array) can be used in any monad
> and that immediately leads me to using MPTC+FD. moreover, problems with
> resolving class overloading and other deficiencies of current
> unofficial Hugs/GHC standard are permanently strikes me

Libraries are a means, not an end.  The fact still remains.  Most
programs don't need MPTCs in an essential way.  It's convenient to have
them, but they are not essential.

> i had a class which defines "default" reference type for monads:
> class Ref m r | m->r where
>   newRef :: a -> m (r a)
>   readRef :: r a -> m a
>   writeRef :: r a -> a -> m ()
> instance Ref IO IORef where ...
> instance Ref (ST s) (STRef s) where ...
> this class allows to write monad-independent code, for example:
> doit = do x <- newRef 0
>           a <- readRef x
>           writeRef x (a+1)
>           readRef x
> can be runned in IO or ST monads, or in any monad derived from IO/ST
> (with appropriate instance Ref definitions). As you can see, even such
> small example require using FDs.

> this will allow to rewrite my Ref class as:
> type Ref IO = IORef
>      Ref (ST s) = STRef s

You are going in the right direction, but what you want here are
associated types; i.e., you want type functions that are open and can be
extended (in the same way as classes can be extended by adding new
instances).  Your example reads as follows with associated types:

  class Monad m => RefMonad m where
    type Ref m :: * -> *
    newRef :: a -> m (Ref m a)
    readRef :: Ref m a -> m a
    writeRef :: Ref m a -> a -> m ()

  instance RefMonad IO where 
    type Ref IO = IORef
  instance RefMonad (ST s) where
    type Ref (ST s) = STRef s

My statement remains:  Why use a relational notation if you can have a
functional one?  (The RefMonad class is btw very similar to a functor of
ML's module system.[*])  See

for more details on associated types.


[*] Cf

More information about the Haskell-prime mailing list