Next: , Previous: , Up: Type classes   [Contents]

10.7 Type class constraints on instance declarations

Typeclass constraints may also be placed upon instance declarations. The arguments of such constraints must be either type variables or ground types. Each constraint must contain at least one variable argument and all variables that appear in the arguments must be type variables that appear in the types in the instance declaration.

For example, consider the following declaration of a type class of types that may be printed:

:- typeclass portrayable(T) where [
        pred portray(T::in, io.state::di, io.state::uo) is det

The programmer could declare instances such as

:- instance portrayable(int) where [
        pred(portray/3) is io.write_int

:- instance portrayable(char) where [
        pred(portray/3) is io.write_char

However, when it comes to writing the instance declaration for a type such as list(T), we want to be able print out the list elements using the portray/3 for the particular type of the list elements. This can be achieved by placing a type class constraint on the instance declaration, as in the following example:

:- instance portrayable(list(T)) <= portrayable(T) where [
        pred(portray/3) is portray_list

:- pred portray_list(list(T), io.state, io.state) <= portrayable(T).
:- mode portray_list(in, di, uo) is det.

portray_list([], !IO).
portray_list([X | Xs], !IO) :-
	portray(X, !IO),
	io.write_char(' ', !IO),
	portray_list(Xs, !IO).

For abstract instance declarations, the type class constraints on an abstract instance declaration must exactly match the type class constraints on the corresponding non-abstract instance declaration that defines that instance.