(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.2
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.