NOTE — A built-in predicatecall_cleanup/2is implemented in many existing processors to provide similar functionality assetup_call_cleanup/3. It is often used to free temporary resources. In the presence of interrupts (7.12 note c),call_cleanup/2can cause leakage of resources: A processor receiving interrupts between resource allocation andcall_cleanup/2is unable to free the resource timely. For this reason,setup_call_cleanup/3protects goals in a separate argument.
setup_call_cleanup(Setup, Goal, Cleanup) is true
iff call(Setup), call(Goal) is true,
and Cleanup is not replaced by throw/1.
Setup is executed protected from interrupts.
Setup is executed
entirely and the cleanup handler Cleanup is installed
for each solution of Setup.
setup_call_cleanup/3 is interrupted by an
implementation
dependent interrupt (7.12 note c) without leaving an
effect.
Setup, the Goal is called as
in call(Goal) with the cleanup handler present.
Goal has completed execution normally.Goal
Goal, if applicable
Goal, if applicable
Goal
NOTE — The implementation dependence is due to
the varying ability of Prolog processors to detect determinism.
For example, a particular processor may execute a
goal call((call(Goal);fail))
as call(Goal) and vice versa.
Goal or the continuation of Goal
executes a throw/1 (explicitly or implicitly — 7.8.9 a or
b), whose corresponding call of catch/3 is above Goal.Cleanup, the "ball"
of throw/1 will be passed, regardless of the
outcome of Cleanup.
NOTE — As a consequence, the "ball"
of Cleanup is lost in case Cleanup
executes another throw/1.
Goal executes a cut
(explicitly or implicitly) that concerns the cutparent of Goal.Cleanup is called in
the place of the cut.
A cut is performed implicitly for (->)/2 - if-then
(7.8.7), (;)/2 - if-then-else (7.8.8), (\+)/1
(8.15.1), once/1 (8.15.2).
Cleanup is called as once(Cleanup). Failure
of Cleanup is ignored. An explicit or
implicit throw/1 is ignored for c2. Otherwise (c1 or
c3), it is passed to the next matching catch/3.
Cleanup shares bindings and variables
with Setup, Goal and the continuation. The
bindings of Setup are always present. No further bindings
are present in c2 and at the latest moment of c1. In c2, and in the
earliest moment of c1, all bindings are present at the time of calling
the cut. All other cases of c1 are implementation dependent.
A processor may restrict execution of Cleanup in an
implementation dependent manner. E.g., a processor may restrict the
handling of interrupts within Cleanup or limit resource
consumption.
write/1 outputs using standard
operators (6.3.4.4, table 7). Unique variables are written
as _ which is one possible way to
realize the implementation dependent manner of 7.10.5 a)
The different outcomes (labeled either/or) are due to the implementation dependence in c1.
setup_call_cleanup(fail, _, _).
Fails. Neither Goal nor Cleanup is executed.
setup_call_cleanup(true, throw(unthrown),_).
Instantiation error.
setup_call_cleanup(true, true, ( true ; throw(x) )).
Succeeds. No system error.
setup_call_cleanup(true, X = 1, X = 2).
Succeeds, unifying X = 1.
setup_call_cleanup(true, true, X = 2).
Succeeds, unifying X = 2.
setup_call_cleanup(true, X=true,X).
Instantiation error.
setup_call_cleanup(X=throw(ex), true, X).
System error due to uncaught ex.
setup_call_cleanup(true, true, fail).
Succeeds.
setup_call_cleanup(S=1, G=2, C=3).
Either: Succeeds, unifying S = 1, G = 2, C = 3.
Or: Succeeds, unifying S = 1, G = 2. Fails
on backtracking.
setup_call_cleanup((S=1;S=2), G=3, C=4).
a) Either: Succeeds, unifying
S = 1, G = 3, C = 4.
On backtracking proceed to b)
Or: Succeeds, unifying S = 1, G = 3.
On backtracking proceed to b)
b) Either: Succeeds, unifying
S = 2, G = 3, C = 4.
Or: Succeeds, unifying S = 1, G = 3.
Fails on backtracking.
setup_call_cleanup(S=1,G=2,write(S+G)).
Succeeds, unifying S = 1, G = 2.
Either: outputs '1+2'
Or: outputs on backtracking '1+_',
prior to failing.
Or (?): outputs on backtracking '1+2',
prior to failing.
setup_call_cleanup(S=1,(G=2;G=3),write(S+G)).
Succeeds, unifying S = 1, G = 2.
On backtracking, succeeds unifying S = 1 and G = 3.
Either: outputs '1+3'
Or: on backtracking outputs '1+_' prior to failing
Or (?): on backtracking outputs '1+3' prior to failing.
setup_call_cleanup(S=1,G=2,write(S+G>A+B)), A=3, B=4.
Succeeds, unifying S=1,G=2,A=3,B=4.
Either: Outputs one of the following before succeeding
1+2>_+_. Disputable: 1+2>3+_. 1+2>3+4. 1+2>_+4.
Or: outputs one of the above outputs on backtracking
prior to failing.
setup_call_cleanup(S=1,(G=2;G=3,throw(x)),write(S+G)).
Succeeds, unifying S = 1, G = 2.
On backtracking, outputs '1+_' prior
to system error due to uncaught x.
setup_call_cleanup(open(f,read,S),read(S,X),close(S)).
Opens file f for reading, reads a term and closes the file.
Succeeds, unifying S with the term read.
The file is closed, either immediately or on backtracking.
In any case, even if there is an error in read, the
file will be closed.
setup_call_cleanup(S=1,(G=2;G=3),write(S+G>B))), B=4, !.
Outputs '1+2>4'. Succeeds, unifying S = 1, G = 2, B = b.
setup_call_cleanup(S=1,G=2,write(S+G>B)),B=3,!.
Either: Outputs '1+2>3'. Succeeds, unifying
S = 1, G = 2, B = 3.
Or: Outputs '1+2>_'. Succeeds, unifying
S = 1, G = 2, B = 3.
setup_call_cleanup(S=1,(G=2;fail),write(S+G>B)), B=3, !.
Same as above.
setup_call_cleanup(S=1,(G=2;S=2),write(S+G>B)), B=3, !.
Same as above.
setup_call_cleanup(S=1,(G=2;G=3), write(S+G>B)), B=4, throw(x).
Outputs '1+_>_'. system_error due to uncaught x.
setup_call_cleanup(S=1,(G=2;G=3), write(S+G>B)), B=4, !, throw(x).
Outputs '1+2>4'. system_error due to uncaught x.
catch(setup_call_cleanup(true,throw(goal),throw(cl)), Pat, true). Succeeds unifying Pat = goal. catch(( setup_call_cleanup(true,(G=1;G=2),throw(cl)), throw(cont)), Pat, true). Succeeds unifying Pat = cont.
Cleanup (Manual is correct though).