The paper says:
> We have chosen this implementation scenario in our Kernel
> Prolog compiler which provides a return/1 operation to exit
> an engine's emulator loop with an arbitrary answer pattern,
> possibly before the end of a successful derivation.
Its only used in the kernel prolog specific implementation
of throw/1. You could use the ISO throw/1 directly. Its not
meant to be part of the fluent interface. This is my guess
BTW: I wonder how you simulate the trailing of fluents.
setup_call_cleanup/3 doesn't provide trailing. Trailing
means that a fluent should survive a cut.
That we have also here a gap in the ISO core standard,
was recently also noticed by Paulo Moura, he tweeted:
"Prolog lacks a logical/standard solution to handle
global backtrackable state changes, pushing users
to use nasty hacks or to highjack DCGs."
I can only agree, provided Paulo Moura means the same
as I have in mind. And I guess he is refering to another
paper by Paul Tarau which shows trailing via DCGs. But
I might be wrong.
Paul Tarau in the present paper seems to have an API
for trailing which consist simply of a getTrail() method
and then a push() method. I could be also wrong here,
that it is a cut trailing and not a variable trailing
as I am assuming.
In Jekejeke Prolog I have a similar mechanism, not as
an API on the Java level, but as a predicate on
the Prolog level.
The predicate installs an unbind handler A and immediately
succeeds. The unbind handler is invoked during a redo or a close.
So you would create a thread based Tarau fluent as
follows in Jekejeke Prolog (using a yet unpublish
thread library and queuing library):
start_fluent(Answer, Goal, Control, Result) :-
enum_fluent(Answer, Goal, Control, Result)),
sys_undo(Control ! stop))).
enum_fluent(Answer, Goal, Control, Result) :-
Control ? Command,
(Command == stop -> !; fail),
Result ! the(Answer),
Control ? Command,
(Command == stop -> !; fail); Result ! no).
next_fluent(Control, Result, Answer) :-
Control ! next,
Result ? Answer.
Control ! stop.
But the name fluent for the above thing is kind of
an abuse, if it is implemented without a thread. Then
its just an iterator. With threads, its a little bit
more but no so much more.
The more general model would be to just allow
threads to use (?)/2 (receive) and (!)/2 (send) as
they wish. The Tarau "fluent" is then an instance of
a different problem, namely how to return a collection
of results on a single request.
Also it begs a little bit the question whether we
should always stop a thread during undo, and not
also have scenarios where a thread should live
longer than its creation point.
The wish for sys_undo/1, respectively my wish for
a sys_undo/1 standardization rather stems from
constraint programming, where we want to clean-up
constraints during backtracking.
But the constraint clean-up should not be induced
by a cut. We all assume that this does not happen,
for example in SWI-Prolog, constraints survive a
cut, but not a redo:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.6)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
?- X #< 10.
X in inf..9.
?- X #< 10, !.
X in inf..9.
?- X #< 10; X #>= 10.
X in inf..9 ;
X in 10..sup.
sys_undo/1 is borrowed/inspired from SICStus undo/1.
Mercury has a very elaborate trailing API that
can do a little bit more than getTrail() and push().
Julio Di Egidio schrieb: