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.

[ISO]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)
True if Goal cannot be proven. Retained for compatibility only. New code should use \+/1.
[ISO]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 infinitely 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 iterative 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 choice-point 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 possible choice-points it created are destroyed (as once/1). If cleanup throws an exception this is executed as normal.bugDuring the execution of Cleanup, garbage collection and stack-shifts are disabled.

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 choice-points.
fail
Goal failed.
!
Goal succeeded with choice-points and these are now discarded by the execution of a cut (or other 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 choice-point left by repeat is killed by a cut.

The call_cleanup/2 can also be used to test determinism of a goal, providing a portable alternative to deterministic/1:

?- call_cleanup((X=1;X=2), Det=yes).

X = 1 ;

X = 2,
Det = yes ;

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.
setup_and_call_cleanup(:Setup, :Goal, :Cleanup)
This predicate is introduced to allow for the proper definition of predicates with temporary side-effects under asynchronous interrupts from call_with_time_limit/2 (package clib) or thread_signal/2. It behaves as if defined below, but the Cleanup handler is also called if the interrupt occurs between Setup and the call_cleanup/2 call.
setup_and_call_cleanup(Setup, Goal, Cleanup) :-
        Setup,
        call_cleanup(Goal, Cleanup).