4.11.16 The meta_predicate Declaration

Sometimes 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, then 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:

  1. A is of the form Module:Goal.
  2. A is a variable and the same variable appears in the head of the clause in a module-name-expansion position.

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:

:

requires module name expansion

If the argument will be treated as a goal, then it is better to explicitly indicate this using an integer; see the next item.

nsuppressed

a non-negative integer.

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 runtime. 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, then the generic : is always safe to use, but will give less accurate results from source analysis tools.

*
+
-
?

ignored

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 release 4.1, only : (colon) was used and the integer form was undocumented (but supported, e.g. by the cross referencer).



Send feedback on this subject.