`class` declarations

    The general concepts behind classes, instances, overloading etc. were introduced in section 2.1. A new class is declared using the following:

    topDefn ::= class [ context => ] classId {tyVarId }[ | funDep ] where {
                 {varId :: ctxType ; }
                 }
    

    classId is the newly declared class. It can be polymorphic, if tyVarId's exist; these are called the parameters of the type class. The tyVarId's may themselves be constrained by context, in which case the classes named in context are called the "super-classes" of this class. The "varId::ctxType" list declares the class method names and their types.

    Example (from the Prelude):

    class Literal a where
        fromInteger :: Integer -> a
    

    This defines the class Literal. It says that any type a in this class must have a method (a function) called fromInteger that converts an Integer value into the type a. In fact, this is the mechanism the BH uses to interpret literal constants, e.g., to resolve whether a literal like 6847 is to be interpreted as a signed integer, an unsigned integer, a floating point number, a bit value of 10 bits, a bit value of 8 bits, etc. (This is described in more detail in Section 5.3.)

    Example (from the Prelude):

    class (Literal a) => Arith a where
        (+) :: a -> a -> a
        (-) :: a -> a -> a
        negate :: a -> a
        (*) :: a -> a -> a
    

    This defines the class Arith with super-class Literal. It says that for any type a that is a member of the class Arith, it must also be a member of the class Literal, and it must have four methods with the given names and types. Said another way, an Arith type must have a way to convert integer literals into that type, and it must have addition, subtraction, negation and multiplication defined on it.

    The optional funDep section specifies functional dependencies between the parameters of the type class:

    funDep ::= { {tyVarId }-> {tyVarId }, }
    

    These declarations specify that a type parameter may be determined uniquely by certain other type parameters. For example:

    class Add x y z | x y -> z, y z -> x, z x -> y
    

    Here, the class declaration says that for any triple of types x, y and z that are in the class Add, any two of the types uniquely determines the remaining type, i.e.,

    • x and y uniquely determine z,
    • y and z uniquely determine x, and
    • z and z uniquely determine y.

    See section 8.1 for more detailed insights into the use of functional dependencies.

    NOTE: Functional dependencies are not currently checked by the compiler.