Home Contents Index Summary Previous Next

4.8 Meta-Call Predicates

Meta call predicates are used to call terms constructed at run time. The basic meta-call mechanism offered by SWI-Prolog is to use variables as a subclause (which should of course be bound to a valid goal at runtime). A meta-call is slower than a normal call as it involves actually searching the database at runtime for the predicate, while for normal calls this search is done at compile time.

call(+Goal)
Invoke Goal as a goal. Note that clauses may have variables as subclauses, which is identical to call/1.

call(+Goal, +ExtraArg1, ...)
Append ExtraArg1, ExtraArg2, ... to the argument list of Goal and call the result. For example, call(plus(1), 2, X) will call plus/3, binding X to 3.

The call/[2..] construct is handled by the compiler, which implies that redefinition as a predicate has no effect. The predicates call/[2-6] are defined as true predicates, so they can be handled by interpreted code.

apply(+Term, +List)
Append the members of List to the arguments of Term and call the resulting term. For example: apply(plus(1), [2, X]) will call plus(1, 2, X). apply/2 is incorporated in the virtual machine of SWI-Prolog. This implies that the overhead can be compared to the overhead of call/1. New code should use call/[2..] if the length of List is fixed, which is more widely supported and faster because there is no need to build and examine the argument list.

not(+Goal)
Succeeds when Goal cannot be proven. Retained for compatibility only. New code should use \+/1.

once(+Goal)
Defined as:


once(Goal) :-
        Goal, !.

once/1 can in many cases be replaced with ->/2. The only difference is how the cut behaves (see !/0). The following two clauses are identical:


1) a :- once((b, c)), d.
2) a :- b, c -> d.

ignore(+Goal)
Calls Goal as once/1, but succeeds, regardless of whether Goal succeeded or not. Defined as:


ignore(Goal) :-
        Goal, !.
ignore(_).

call_with_depth_limit(+Goal, +Limit, -Result)
If Goal can be proven without recursion deeper than Limit levels, call_with_depth_limit/3 succeeds, binding Result to the deepest recursion level used during the proof. Otherwise, Result is unified with depth_limit_exceeded if the limit was exceeded during the proof, or the entire predicate fails if Goal fails without exceeding Limit.

The depth-limit is guarded by the internal machinery. This may differ from the depth computed based on a theoretical model. For example, true/0 is translated into an inlined virtual machine instruction. Also, repeat/0 is not implemented as below, but as a non-deterministic foreign predicate.


repeat.
repeat :-
        repeat.

As a result, call_with_depth_limit/3 may still loop inifitly on programs that should theoretically finish in finite time. This problem can be cured by using Prolog equivalents to such built-in predicates.

This predicate may be used for theorem-provers to realise techniques like iterrative deepening. It was implemented after discussion with Steve Moyle smoyle@ermine.ox.ac.uk.

call_cleanup(:Goal, +Catcher, :Cleanup)
Calls Goal. If Goal is completely finished, either by deterministic success, failure, its choicepoint being cut or raising an exception and Catcher unifies to the termination code (see below), Cleanup is called. Success or failure of Cleanup is ignored and possibly choicepoints it created are destroyed (as once/1). If cleanup throws an exception this is executed as normal. (25)

Catcher is unified with a term describing how the call has finished. If this unification fails, Cleanup is not called.

exit
Goal succeeded without leaving any choicepoints.

fail
Goal failed.

!
Goal succeeded with choicepoints and these are now discarded by the execution of a cut (or orther pruning of the search tree such as if-then-else).

exception(Exception)
Goal raised the given Exception.

Typical use of this predicate is cleanup of permanent data storage required to execute Goal, close file-descriptors, etc. The example below provides a non-deterministic search for a term in a file, closing the stream as needed.


term_in_file(Term, File) :-
        open(File, read, In),
        call_cleanup(term_in_stream(Term, In), _, close(In)).

term_in_stream(Term, In) :-
        repeat,
        read(In, T),
        (   T == end_of_file
        ->  !, fail
        ;   T = Term
        ).

Note that this predicate is impossible to implement in Prolog other then reading all terms into a list, close the file and call member/2 because without call_cleanup/3 there is no way to gain control if the choicepoint left by repeat is killed by a cut.

This predicate is a SWI-Prolog extension. See also call_cleanup/2 for compatibility to other Prolog implementations.

call_cleanup(:Goal, :Cleanup)
This predicate is equivalent to call_cleanup(Goal, _, Cleanup), calling Cleanup regardless of the reason for termination and without providing information. This predicate provides compatibility to a number of other Prolog implementations.