(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.bugDuring the execution of Cleanup, garbage collection and stack-shifts are disabled.
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.