This document describes
the transformation that the compiler does to implement type classes.
Tranformation of code using type classes
Every predicate which has a typeclass constraint is given an extra
argument for every constraint in the predicate's type declaration.
The argument is the "dictionary", or "typeclass_info" for the typeclass.
The dictionary contains pointers to each of the class methods.
Representation of a typeclass_info:
The typeclass_info is represented in two parts (the typeclass_info
itself, and a base_typeclass_info), in a similar fashion to the
type_info being represented in two parts (the type_info and the
type_ctor_info).
The base_typeclass_info contains:
- the sum of the number of constraints on the instance decl.
and the number of unconstrained type variables
from the head of the instance decl. (`n1')
- the number of constraints on the instance decl. (`n2')
- the number of constraints on the typeclass decl. (`n3')
- the number of parameters (type variables) from
the typeclass decl. (`n4')
- the number of methods from the typeclass decl. (`n5')
- pointer to method #1
- ...
- pointer to method #n5
The typeclass_info contains:
- a pointer to the base typeclass info
- type info for unconstrained type var #1 from the instance decl
- ...
- type info for unconstrained type var #(n1-n2) from the
instance decl
- typeclass info #1 for constraint on instance decl
- ...
- typeclass info #n2 for constraint on instance decl
- typeclass info for superclass #1
- ...
- typeclass info for superclass #n3
- type info #1
- ...
- type info #n4
The base_typeclass_info is produced statically, and there is one for
each instance declaration. For each constraint on the instance
declaration, the corresponding typeclass_info is stored in the second
part.
eg. for the following program:
:- typeclass foo(T) where [...].
:- instance foo(int) where [...].
:- instance foo(list(T)) <= foo(T) where [...].
The typeclass_info for foo(int) is:
- The base_typeclass_info:
- 0 (there are no unconstrained type variables and no constraints)
- 0 (there are no constraints on the instance decl)
- 0 (there are no constraints on the typeclass decl)
- 1 (this is a single-parameter type class)
- n5 (the number of methods)
- pointer to method #1
- ...
- pointer to method #n5
- The typeclass_info:
- a pointer to the base typeclass info
- type_info for int
The typeclass_info for foo(list(T)) is:
- The base_typeclass_info:
- 1 (no unconstrained tvars, 1 constraint on the instance decl)
- 1 (there is 1 constraint on the instance decl)
- 0 (there are no constraints on the typeclass decl)
- 1 (this is a single-parameter type class)
- n5 (the number of methods)
- pointer to method #1
- ...
- pointer to method #n5
- The typeclass_info contains:
- a pointer to the base typeclass info
- typeclass info for foo(T)
- type_info for list(T)
If the "T" for the list is known, the whole typeclass_info will be static
data. When we do not know until runtime, the typeclass_info is constructed
dynamically.
Example of transformation
Take the following code as an example (assuming the declarations above),
ignoring the requirement for super-homogeneous form for clarity:
:- pred p(T1) <= foo(T1).
:- pred q(T2, T3) <= foo(T2), bar(T3).
:- pred r(T4, T5) <= foo(T4).
p(X) :- q([X], 0), r(1, 0).
We add an extra argument for each type class constraint, and one
argument for each unconstrained type variable.
:- pred p(typeclass_info(foo(T1)), T1).
:- pred q(typeclass_info(foo(T2)), typeclass_info(bar(T3)), T2, T3).
:- pred r(typeclass_info(foo(T4)), type_info(T5), T4, T5).
We transform the body of p to this:
p(TypeClassInfoT1, X) :-
BaseTypeClassInfoT2 = base_typeclass_info(
1,
1,
0,
1,
n5, (ie. the number of methods)
...
... (The methods for the foo class from the list
... instance)
...
),
TypeClassInfoT2 = typeclass_info(
BaseTypeClassInfoT2,
TypeClassInfoT1,
<type_info for list(T1)>),
BaseTypeClassInfoT3 = base_typeclass_info(
0,
0,
0, (presuming bar has no superclasses)
1,
...
... (The methods for the bar class from the int
... instance)
...
),
TypeClassInfoT3 = typeclass_info(
BaseTypeClassInfoT3,
<type_info for int>),
q(TypeClassInfoT2, TypeClassInfoT3, [X], 0),
BaseTypeClassInfoT4 = baseclass_type_info(
0,
0,
0,
1,
...
... (The methods for the foo class from the int
... instance)
...
),
TypeClassInfoT4 = typeclass_info(
BaseTypeClassInfoT4,
<type_info for int>),
r(TypeClassInfoT4, <type_info for int>, X, 0).
Last update was $Date: 2000/05/10 18:09:38 $ by $Author: fjh $@cs.mu.oz.au.