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, 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 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(:, +, -).
The significant argument in the mysort/3 term is the :, which indicates that module name expansion is required for this argument. 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(:, +, ?),
             sam_sort(+, :, +, +, ?).
     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
non-negative integer
same as :
+, -, *

The reason for allowing a non-negative integer as an alternative to : is that this may be used in the future to supply additional information to the cross-referencer (library(xref)) and to the Prolog compiler. An integer n is intended to mean that that argument is a term that will be supplied n additional arguments. Thus, in the example above where the meta-argument is the name of a comparison routine that would be called with two arguments, it would be appropriate to write the integer 2 instead of a :.

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.