meta_predicate
DeclarationSometimes a user-defined predicate will require module name expansion (see
ref-mod-mne). This can be specified by providing a
meta_predicate
declaration for that procedure.
Module name expansion is needed whenever the argument of a predicate has some module-dependent meaning. For example, if this argument is a goal that is to be called, it will be necessary to know in which module to call it—or, if the argument is a clause to be asserted, in which module it should go.
Consider, for example, a sort routine to which the name of the
comparison predicate is passed as an argument. In this example, the
comparison predicate should be called, with two arguments like the
built-in @=</2
, with respect to the module
containing the call to the sort routine. Suppose that the sort
routine is
mysort(CompareProc, InputList, OutputList)
An appropriate meta_predicate
declaration for this is
:- meta_predicate mysort(2, +, -).
The significant argument in the mysort/3
term is the ‘2’,
which indicates that module name expansion is required for this argument
and that two additional arguments will be added when this argument is
invoked as a goal.
This means that
whenever a goal mysort(
A,
B,
C)
appears in a clause, it will be
transformed at load time into mysort(
M:
A,
B,
C)
, where M is the
source module. There are some exceptions to this compile-time
transformation rule; the goal is not transformed if either of the
following applies:
The reason for (2)
is that otherwise module name expansion could
build larger and larger structures of the form Mn: ... :M2:M1:Goal.
For example, consider the following program fragment adapted from the
library (see library(samsort)
for the full program):
:- module(samsort, [samsort/3]). :- meta_predicate samsort(2, +, ?), sam_sort(+, 2, +, +, ?). samsort(_, [], []) :- !. samsort(Order, List, Sorted) :- sam_sort(List, Order, [], 0, Sorted). . . .
Normally, the sam_sort/5
goal in this example would have the module name of its
second argument expanded thus:
sam_sort(List, samsort:Order, [], 0, Sorted)
because of the meta_predicate
declaration. However, in this
situation the appropriate source module will have already been
attached to Order because it is the first argument of samsort/3
,
which also has a meta_predicate
declaration. Therefore it is
not useful to attach the module name (samsort
) to Order in the call of
sam_sort/5
.
The argument of a meta_predicate
declaration can be a term, or a
sequence of terms separated by commas. Each argument of each of these
terms must be one of the following:
If the argument will be treated as a goal, it is better to
explicitly indicate this using an integer; see the next item.
This is a special case of ‘:’ which means that the argument can be
made into a goal by adding nsuppressed additional arguments. E.g., if
the argument will be passed to call/1
then 0
(zero)
should be used.
An integer is treated the same as ‘:’ above by the SICStus run-time. Other tools, such as the cross referencer (see The Cross-Referencer) and the SICStus Prolog IDE (see SICStus Prolog IDE), will use this information to better follow predicate references in analyzed source code.
If the number of extra arguments is unknown or varies, the generic
:
is always safe to use, but will give less accurate results from
source analysis tools.
The reason for ‘+’, ‘-’ and ‘?’ is simply so that the information
contained in a DEC-10 Prolog-style “mode” declaration may be represented
in the meta_predicate
declaration if you wish. There are many examples of
meta_predicate
declarations in the library.
Prior to SICStus Prolog 4.1, only :
(colon) was used and the
integer form was undocumented (but supported, e.g. by the cross
referencer).