Mode declarations for predicates and functions may also have inst parameters. However, such parameters must be constrained to be compatible with some other inst. In a predicate or function mode declaration, an inst of the form ‘InstParam =< Inst’, where InstParam is a variable and Inst is an inst, states that InstParam is constrained to be compatible with Inst, that is, InstParam represents some inst that can be used anywhere where Inst is required. If an inst parameter occurs more than once in a declaration, it must have the same constraint on each occurrence.
For example, in the mode declaration
:- mode append(in(list_skel(I =< ground)), in(list_skel(I =< ground)), out(list_skel(I =< ground))) is det.
I is an inst parameter which is constrained to be ground.
If ‘append’ is called with the first two arguments having an inst of, say,
‘list_skel(bound(f))’ then after ‘append’ returns, all three arguments
will have inst ‘list_skel(bound(f))’.
If the mode of append had been simply
:- mode append(in(list_skel(ground)), in(list_skel(ground)), out(list_skel(ground))) is det.
then we would only have been able to infer an inst of ‘list_skel(ground)’ for the third argument, not the more specific inst.
Note that attempting to call ‘append’ when the first two arguments do not have ground insts (e.g. ‘list_skel(bound(g(free)))’) is a mode error because it violates the constraint on the inst parameter.
To avoid having to repeat a constraint everywhere that an inst parameter occurs, it is possible to list the constraints after the rest of the mode declaration, following a ‘<=’. E.g. the above example could have been written as
:- (mode append(in(list_skel(I)), in(list_skel(I)), out(list_skel(I))) is det) <= I =< ground.
Note that in the current Mercury implementation this syntax requires parentheses around the ‘mode(…) is Det’ part of the declaration.
Also, if the constraint on an inst parameter is ‘ground’ then it is not necessary to give the constraint in the declaration. The example can be further shortened to
:- mode append(in(list_skel(I)), in(list_skel(I)), out(list_skel(I))) is det.
Constrained polymorphic modes are particularly useful when passing objects with higher-order types to polymorphic predicates since they allow the higher-order mode information to be retained (see Higher-order).