Haskell' - class aliases

Simon Peyton-Jones simonpj at microsoft.com
Fri Apr 25 12:37:17 EDT 2008


OK here's a question about class alisas. You propose:

   class Foo a where
        foo :: a -> [a]
        foo x = []
   class Bar a where
        bar :: a -> a
        bar x = [x]

   class alias FooBar a = (Foo a, Bar a) where
        foobar :: a -> a
        foobar x = x

        foo x = bar x

I have a few minor questions about this that'd be worth clarifying on your main page
  (a) I assume you can add a method 'foobar' not declared
        in either Foo or Bar.  Your very first example has this.
        But it's contradicted later when you say that "One can declare an instance
        of Num either by giving separate instances for Eq, Additive, Multiplicative"

  (b) And I assume that you don't need to repeat the type
        signatures for 'foo' and 'bar'.

  (c) I think you intend that you can override the default methods
        for foo and bar; and I have done so for method 'foo'.

Question: how does the above differ from this?

   class (Foo a, Bar a) => FooBarSC a where
        foobar :: a -> a

Here Foo, Bar are simply superclasses.  From the point of view of a type signature there *no* difference:

        f :: (FooBarSC a) => ...

gives access to all the methods of Foo and Bar.  So what's the difference?

        Answer (I believe): when you give an instance of FooBar
        you give implementations for all methods of
        Foo, Bar, and FooBar.

So the obvious question is: do we really need a new construct?  Why not just use FooBarSC?  Then we'd have to allow you to give implementations for superclass methods too:
        instance FooBarSC Int where
          foobar = ...
          foo = ...
          bar = ...

I think I believe (like you) that this is a bad idea.  The main reason is that it's a totally unclear whether, given a FooBarSC Int instance declaration, should there be an instance for (Foo Int), always, never, or optionally?

However, I think you might want to articulate the reasons carefully, because we have two features that are really extremely close.

To put it another way, you could imagine re-expressing your proposal like this:

  class (Eq a) && (Additive a, Multiplicative a) => Num a

meaning this: when you give an instance for (FooBar T) you

 * MUST give implementations for the methods
        of Addititive and Applicative

 * MUST NOT give implementations for methods of Eq;
        rather the Eq T instance must be in scope.

This is, I believe, what you mean by
  class alias Num a = Eq a => (Additive a, Multiplicative a)

Now I'm not necessarily suggesting this as concrete syntax.  But my point is that you're really asking for small modification of the existing superclass mechanism, that divides the superclasses into two groups, the "flat" ones (like Additive and Multiplicative) and the "nested" ones (like Eq).  Is that right? If so, a syntax that is more suggestive of the current superclass declaration looks better to me.

This close relationship also suggests strongly that the answer to (a) above should be 'yes', since you can certainly add methods to a class with superclasses.

I won't say more until I'm sure I've understood your intent.


More information about the Haskell-prime mailing list