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.
read(Goal), call(Goal)
. Also a meta
predicates such as ignore/1
are defined using call:
ignore(Goal) :- call(Goal), !. ignore(_).
Note that a plain variable as a body term acts as call/1 and the above is equivalent to the code below. SWI-Prolog produces the same code for these two progams and listing/1 prints the program above.
ignore(Goal) :- Goal, !. ignore(_).
Note that call/1 restricts the scope of the cut (!/0). A cut inside Goal only affects choice points created by Goal.
call(plus(1), 2,
X)
will call plus(1, 2, X)
, binding X to
3.
The call/[2..] construct is handled by the compiler. The predicates call/[2-8] are defined as real (meta-)predicates and are available to inspection through current_predicate/1, predicate_property/2, etc.74Arities 2..8 are demanded by ISO/IEC 13211-1:1995/Cor.2:2012. Higher arities are handled by the compiler and runtime system, but the predicates are not accessible for inspection.75Future versions of the reflective predicate may fake the presence of call/9.. . Full logical behaviour, generating all these pseudo predicates, is probably undesirable and will become impossible if max_arity is removed.
apply(plus(1), [2, X])
calls
plus(1, 2, X)
. New code should use call/[2..] if the length
of
List is fixed.once(Goal) :- call(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 below are identical. Be careful about the
interaction with
;/2. The library(apply_macros)
library defines an inline expansion of once/1,
mapping it to (Goal->true;fail)
. Using the full
if-then-else constructs prevents its semantics from being changed when
embedded in a ;/2
disjunction.
1) a :- once((b, c)), d. 2) a :- b, c -> d.
ignore(Goal) :- Goal, !. ignore(_).
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 inline 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. See also call_with_inference_limit/3. It was implemented after discussion with Steve Moyle smoyle@ermine.ox.ac.uk.
call(Goal)
, but limits the number of
inferences
for each solution of Goal.76This
predicate was realised after discussion with Ulrich Neumerkel and Markus
Triska.. Execution may terminate as follows:
inference_limit_exceeded
into its execution. After termination of Goal,
Result is unified with the atom
inference_limit_exceeded
.
Otherwise,!
.true
.An inference is defined as a call or redo on a predicate. Please note that some primitive built-in predicates are compiled to virtual machine instructions for which inferences are not counted. The execution of predicates defined in other languages (e.g., C, C++) count as a single inference. This includes potentially expensive built-in predicates such as sort/2.
Calls to this predicate may be nested. An inner call that sets the limit below the current is honoured. An inner call that would terminate after the current limit does not change the effective limit. See also call_with_depth_limit/3 and call_with_time_limit/2.
(once(Setup), Goal)
. If Setup succeeds, Cleanup
will be called exactly once after Goal is finished: either on
failure, deterministic success, commit, or an exception. The execution
of Setup is protected from asynchronous interrupts like
call_with_time_limit/2
(package clib) or thread_signal/2.
In most uses,
Setup will perform temporary side-effects required by Goal
that are finally undone by Cleanup.
Success or failure of Cleanup is ignored, and choice points it created are destroyed (as once/1). If Cleanup throws an exception, this is executed as normal while it was not triggered as the result of an exception the exception is propagated as normal. If Cleanup was triggered by an exception the rules are described in section 4.10.1
Typically, this predicate is used to cleanup 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) :- setup_call_cleanup(open(File, read, In), 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 it is impossible to implement this predicate in Prolog. The closest approximation would be to read all terms into a list, close the file and call member/2. Without setup_call_cleanup/3 there is no way to gain control if the choice point left by repeat/0 is removed by a cut or an exception.
setup_call_cleanup/3 can also be used to test determinism of a goal, providing a portable alternative to deterministic/1:
?- setup_call_cleanup(true,(X=1;X=2), Det=yes). X = 1 ; X = 2, Det = yes ;
This predicate is under consideration for inclusion into the ISO standard. For compatibility with other Prolog implementations see call_cleanup/2.
setup_call_cleanup(Setup, Goal, Cleanup)
with
additional information on the reason for calling Cleanup.
Prior to calling Cleanup, Catcher unifies with the
termination code (see below). If this unification fails, Cleanup
is
not called.
!
?- setup_call_catcher_cleanup(true, (X=1;X=2), Catcher, writeln(Catcher)), throw(ball). external_exception(ball) ERROR: Unhandled exception: Unknown message: ball
setup_call_cleanup(true, Goal, Cleanup)
. This is
provided for compatibility with a number of other Prolog implementations
only. Do not use call_cleanup/2
if you perform side-effects prior to calling that will be undone by Cleanup.
Instead, use setup_call_cleanup/3
with an appropriate first argument to perform those side-effects.b_assertz(Term) :- assertz(Term, Ref), undo(erase(Ref)).
Without undo/1 we can achieve something similar by leaving a choicepoint using the almost portable77assertz/2 is not part of the ISO standard but supported by multiple systems. alternative below.
b_assertz(Term) :- assertz(Term, Ref), ( true ; erase(Ref), fail ).
The undo/1 based solution avoids leaving a choice point open and, more importantly, keeps undoing the assert also if the choice point from the second alternative is pruned.
Currently the following remarks apply
permission_error
exception.
See also snapshot/1 and transaction/1.