87 lines
2.6 KiB
Markdown
87 lines
2.6 KiB
Markdown
|
+++
|
||
|
title = "`class` declarations"
|
||
|
weight = 1
|
||
|
+++
|
||
|
|
||
|
The general concepts behind classes, instances, overloading etc. were
|
||
|
introduced in section [2.1](fixme). 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):
|
||
|
|
||
|
```hs
|
||
|
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 `6`847 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](fixme).)
|
||
|
|
||
|
|
||
|
Example (from the Prelude):
|
||
|
|
||
|
```hs
|
||
|
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:
|
||
|
|
||
|
```hs
|
||
|
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](fixme) for more detailed insights into
|
||
|
the use of functional dependencies.
|
||
|
|
||
|
> **NOTE:**
|
||
|
> Functional dependencies are not currently checked by the compiler.
|