3.9 KiB
+++
title = "instance
declarations"
weight = 1
+++
A type can be declared as an instance of a class in two ways. The
general mechanism is the instance
declaration; a convenient shortcut
that can sometimes be used is the deriving
mechanism.
The general instance
declaration grammar is the following:
topDefn ::= instance context => classId {type }where
{ {localDefn ; }}
This can be read as saying that the type type is an instance of class classId, provided the constraints of context hold, and where the localDefn's specify the implementation of the methods of the class.
Sometimes, when a new type is defined using a data
declaration, it can
simultaneously be made a member of certain useful, predefined classes,
allowing the compiler to choose the "obvious" implementation of the
class methods. This is done using the deriving
qualification to a
data
declaration (described in section
4.1) or to a
struct
declaration (described in section
4.2). The only classes for which deriving
can
be used for general types are Bits
, Eq
and Bounded
. Furthermore,
deriving
can be used for any class if the type is a data type that is
isomorphic to a type that has an instance for the derived class.
Deriving Bits
The instances derived for the Bits
class can be described as follows:
- For a
struct
type it is simply the the concatenation of the bits for all the fields. The first field is in the leftmost (most significant) bits, and so on. - For a
data
type, all values of the type occupy the same number of bits, regardless of which disjunct (constructor) it belongs to. This size is determined by the largest disjunct. The leftmost (most significant) bits are a code (a tag) for the constructor. As few bits as possible are used for this. The first constructor in the definition is coded 0, the next constructor is coded 1, and so on. The size of the rest of the bits is determined by the largest numbers of bits needed to encode the fields for the constructors. For each constructor, the fields are laid out left to right, and the concatenated bits are stored right justified (i.e., at the least significant bits). For disjuncts that are smaller than the largest one, the bits between the constructor code and the field bits, if any, are "don't care" bits.
Examples: The type
data Bool = False | True
uses one bit. False
is represented by 0 and True
by 1.
struct Två = { första :: Bit 8; andra:: Bit 16 }
uses 24 bits with första
in the upper 8 bits and andra
in the lower 16.
data Maybe a = Nothing | Just
a will use 1+n
bits,
where n
bits are needed to represent values of type a
. The extra bit
will be the most significant bit and it will be 0 (followed by $n$
unspecified bits) for Nothing
and 1 (followed by the n
bits for a
)
for Just
.
Deriving Eq
The instances derived for the Eq
class is the natural equality for the
type. For a struct all fields have to be equal, for a data type the
constructors have to be equal and then all their parts.
Deriving Bounded
An instance for Bounded
can be derived for an enumeration type,
i.e., a data type where all constructors are niladic. The minBound
will be the first constructor and the maxBound
will be the last.
Bounded
can also be derived for a struct
type if all the field types
of the struct are Bounded
. The minBound
will be the struct with all
fields having their respective minBound
, and correspondingly for
maxBound
.
Deriving for isomorphic types
A data type with one constructor and one argument is isomorphic to its
type argument. For such a type any one-parameter class can be used, in a
deriving
, for which there is an instance for the underlying type.
Example:
data Apples = Apple (UInt 32) deriving (Literal, Arith)
five :: Apples
five = 5
eatApple :: Apples -\> Apples
eatApple n = n - 1