I am part of a group working on a new language for Microwave hardware
design (MHDL).  As it turns out, we are incorporating almost all of
Haskell 1.2 into it.  When we were working on the standard prelude for
the language, we realized that we would like to have multiple class
parameters to the class definitions.  We looked at the Gofer
functional programming environment [Mark P Jones], because it has
that, but that didn't give us exactly what we wanted.

We are trying to do is the following:

We are trying to define operations on signals flowing thru a system.
We want those signals to have any domain and range, the domain and
range being specified at instantiation time.

        -- Continuous Periodic signal representation
        class CPsig signal domain range where
          shift :: signal -> domain -> signal;
          phase :: signal -> domain;
          magnitude :: signal -> range;

        instance CPSig Fsig Float Float where
          -- shift :: Fsig -> Float -> Float
          shift (Fsig f) x = . . .

          -- phase :: Fsig -> Float
          phase (Fsig f) = . . .

          -- magnitude :: Fsig -> Float
          magnitude (Fsig f) = . . .

        instance CPSig Nsig Int Int where
          -- shift :: Nsig -> Int -> Int
          shift (Nsig f) x = . . .

          -- phase :: Nsig -> Int
          phase (Nsig f) = . . .

          -- magnitude :: Nsig -> Int
          magnitude (Nsig f) = . . .

We cannot do this in Haskell, and we cannot do this in Gofer either
because all type variables in the class signature have to be mentioned
in all the method signatures.

So we decided that maybe what we need for our own language is the
following enhancement to the Haskell class system (this is not a
proposal for extending Haskell, just a question about whether this is
a valid thing to do without messing up the whole typing system of
Haskell):

We keep Haskell's class system (the one type variable in the class
signature that has to be mentioned in all method signatures) and add
an optional list of "template" parameters to the class. The parameters
in this list are not required in the method signatures.  So we keep
Haskell's ease of disambiguation for figuring out which instance
method to use since we only have to worry about the one unique class
parameter, but we still have the power of multiple parameters to the
class.

Class Declarations
------------------

A class declaration introduces a new class and the operations on it.
A class declaration has the general form:

        class c => C u1 ... uk where {
                v1 :: c1 => t1 ; ... ; vn :: cn => tn ;
                valdef1 ; ... ; valdefm }

where k >= 1, n >= 1, m >= 0.

This introduces a new class name C; the type variables u1, ..., uk
are scoped only over the method signatures in the class body.  The
context c specifies the superclasses of C; the only type variables
that may be refered to in the context c are u1, ..., uk.  The class
declaration introduces new class methods v1, ..., vn, whose scope
extends outside the class declaration, with types:

        vi :: for all u1, ..., uk, and w (C u1 ... uk, ci) => ti

The ti _must_ mention u1; they may mention type variables w other than
u1, ..., uk; the type of vi is polymorphic in u1, ..., uk and w.  The
ci may constrain only w; in particular, the ci may not constrain u1,
..., uk.

| Aside:
| The fact that ti _must_ mention u1, but may or may not mention u2,
| ..., uk is the significant change from Gofer (and Haskell, which
| only allows one type variable in the class declaration).  We think
| that this would allow disambiguation with the "ease" of Haskell, but
| still allow us the power of multiple class parameters in class
| declarations.

Example given above.

Default methods for any of the vi may be included in the class
declaration as a normal valdef; no other definitions are permitted.
The default method for vi is used if no binding for it is given in a
particular instance declaration.

Two classes in scope at the same time may not share any of the same
methods.

Instance Declarations
---------------------

An instance declaration introduces an instance of a class.  Let

        class c => C u1 ... uk where { cbody }

be a class declaration.  The general form of the corresponding
instance declaration is:

        instance c' => C (T1 u11 ... u1n) ... (Tk uk1 ... ukn) where
                { d }

where n >= 0, k >= 1 and the Tk's are not type synonyms.  The type
being instanced is (T1 u11 ... u1n).  All the T's are type
constructors applied to the simple type variables ui where the all
ui's have to be distinct.

The declarations d may contain bindings only for the class methods of
C, and may not contain any type signatures since the method signatures
have already been given in the class declaration.

Example given above.

If no binding is given for some class method then the corresponding
default method in the class declaration is used (if present); if such
a default does not exist then the class method at this instance is
implicitly bound to the completely undefined function (of the
appropriate type) and no static error results.


Our question to the gurus is the following:  is this too much to ask?
Are we going to mess up the typing philosophy of Haskell with this?
We are new to functional languages and are just not sure.  We think we
can implement this, but we don't want to make changes to our language
that will make it totally inconsistent with the way the Haskell
type/class system works.

Thanks,

--
Atin Malaviya                  |   [EMAIL PROTECTED]
Software Engineer              |   Voice Mail: (703) 827-5566 ext. 234
Intermetrics Inc.              |


Reply via email to