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
here.
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."
https://twitter.com/LogtalkDotOrg/status/627105057289453568
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.
sys_unbind(A):
The predicate installs an unbind handler A and immediately
succeeds. The unbind handler is invoked during a redo or a close.
http://www.jekejeke.ch/idatab/doclet/prod/docs/15_min/10_docu/02_reference/07_theory/05_system/04_trail.html
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) :-
sys_atomic((thread_create(
enum_fluent(Answer, Goal, Control, Result)),
sys_undo(Control ! stop))).
enum_fluent(Answer, Goal, Control, Result) :-
Control ? Command,
(Command == stop -> !; fail),
(Goal,
Result ! the(Answer),
Control ? Command,
(Command == stop -> !; fail); Result ! no).
next_fluent(Control, Result, Answer) :-
Control ! next,
Result ? Answer.
stop_fluent(Control) :-
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
?- use_module(library(clpfd)).
true.
?- X #< 10.
X in inf..9.
?- X #< 10, !.
X in inf..9.
?- X #< 10; X #>= 10.
X in inf..9 ;
X in 10..sup.
Bye
P.S.:
sys_undo/1 is borrowed/inspired from SICStus undo/1.
P.P.S.:
Mercury has a very elaborate trailing API that
can do a little bit more than getTrail() and push().
Julio Di Egidio schrieb: