I've just played a bit with Hugs 1.3c which implements the type system that is
proposed for Standard Haskell. I came accross a limitation compared to Gofer
which I find quite unfortunate.

As an example for the advantages of multiple parameter classes Mark Jones gives:

  class Collection c a where
       empty  :: c a
       insert :: a -> c a -> c a
       ...

Having the element type of a collection as a parameter enables you to define
collections whose elements are restricted, e.g.

  newtype Set a = Set [a] -- ordered list without duplicates

  instance Ord a => Collection Set a where
    empty  = Set []
    insert = ... -- implementation requires ordering


Several people (e.g. Graeme Moss on this mailing list, John Hughes on the
Standard Haskell discussion list) have pointed out that it would be nice to do
the same thing for monads. Well, in Gofer you can. You just write:

  class MyMonad m a where
    myReturn :: a -> m a
    myBind   :: MyMonad m b => m a -> (a -> m b) -> m b

  instance Ord a => MyMonad Set a where
    myReturn = \x -> Set [x]
    myBind =  bindSet

  bindSet :: (Ord a, Ord b) => Set a -> (a -> Set b) -> Set b
  bindSet = ... 

However, Hugs 1.3c doesn't like this:
ERROR "../test.hs" (line 32): Cannot justify constraints in instance member
binding
*** expression    : myBind
*** type          : (MyMonad Set a, MyMonad Set b) => Set a -> (a -> Set b) ->
Set b
*** given context : (MyMonad Set a, MyMonad Set b)
*** constraints   : Ord b
   

Note that neither Hugs 1.3c nor Gofer have any problems with the type of
`myBind' which is

  (MyMonad m a, MyMonad m b) => m a -> (a -> m b) -> m b

The difference lies in the handling of instances. Vividly speaking, Hugs just
type checks the body of the instance `MyMonad Set a' under the assumption that
`Ord a' is given. Hence it lacks context `Ord b' when type checking `myBind'.
Gofer however recognises that every `MyMonad Set a' has an `Ord a' context.
Hence the `MyMonad Set b' context of `myBind' implies the existence of `Ord b'.

Formally the difference is that the Gofer type system has an additional
predicate entailment rule. Any instance definition extends predicate entailment
such that the defined instance implies its own context. See Section 8.2.3 of
Mark Jones' thesis for details.

Mark Jones just introduced this rule for optimisation reasons. In retrospect he
considers this rule as bad idea, because it can break data abstraction.
I agree with that. However, if the scope of the rule is restricted to the body
of the instance, then it certainly does not break data abstraction. The monad
example shows how useful the rule can be. 

I'd like to hear your opinions,

Olaf


PS:
1. on the Standard Haskell discussion list John Hughes gave a showable and
printable monad as another example.
2. implementing the additional rule is a bit of a problem. It requires
dictionaries of extensible size. This is no problem for Gofer or Hugs because
the internal language is untyped. However, GHC uses FOmega as intermediate
language. I found a simple way to code the required form of subtyping in FOmega,
but it is not `nice'.

-- 
OLAF CHITIL, Lehrstuhl fuer Informatik II, RWTH Aachen, 52056 Aachen, Germany
             Tel: (+49/0)241/80-21212; Fax: (+49/0)241/8888-217
             URL: http://www-i2.informatik.rwth-aachen.de/~chitil/


Reply via email to