Subject: RE: Predicate Determining the port in which was called.

From: "Richard A. O'Keefe" <[email-masked]>
Date: Fri, 11 Aug 2000 12:31:28 +1200 (NZST)

With the given program...
	
		p(Goal) :-
		    (   (write('(call) getting oldest item in que \n'),fail)
		    ;   true
		    ;   (write('(fail) putting back as oldest in que\n'), fail)
		    ),
		    writeq(Goal),nl,Goal,
		    (   (write('(exit)\n'), fail)
		    ;   true
		    ;   (write('(redo) putting that oldest back in as newest\n'),
	fail)
		    ). 
	
Let's start by tidying that up and removing the unnecessary parentheses.

    p(Goal) :-
	(   write('(call) getting oldest item in queue.\n'), fail
	;   true
	;   write('(fail) putting back as oldest in queue.\n'), fail
	),
	writeq(Goal), nl,
	call(Goal),
	(   write('(exit)\n'), fail
	;   true
	;   write('(redo) putting that oldest back in as newest\n'), fail
	). 

?- p(true), fail.
(call) getting oldest item in queue.
true
(exit)
(redo) putting that oldest back in as newest
(fail) putting back as oldest in queue.

?- p((true;true)), fail.
(call) getting oldest item in queue.
true;true
(exit)
(redo) putting that oldest back in as newest
(exit)
(redo) putting that oldest back in as newest
(fail) putting back as oldest in queue.

	-------------------------------------------------------------------
	?- p(member(X,[1,2,3])),X=3.
	-------------------------------------------------------------------
	(call) getting oldest item in que
	member(_G306, [1, 2, 3])
	(exit)
	(redo) putting that oldest back in as newest
	(exit)
	(redo) putting that oldest back in as newest
	(exit)
	X = 3
	Yes
	
	Comment: Close (but one extra iteration)
	
Let's see.  What *SHOULD* it do?
    call, exit (X=1), redo, exit (X=2), redo, exit (X=3)
I see no extra iteration here.  Try it with the tidied code:

?- p(member(X, [1,2,3])), X = 3.
(call) getting oldest item in queue.
member(_G315, [1, 2, 3])
(exit)
(redo) putting that oldest back in as newest
(exit)
(redo) putting that oldest back in as newest
(exit)

X = 3 ;
(redo) putting that oldest back in as newest
(fail) putting back as oldest in queue.

No

This is absolutely perfect behaviour.  Each port that *should* be
visited *is* visited, in the right order, with no omissions and no
extras whatsoever.  Let's revise the code again slightly to see
more clearly what's going on:

    p(Goal) :-
	(   s(call, Goal)
	;   true
	;   s(fail, Goal)
	),
	call(Goal),
	(   s(exit, Goal)
	;   true
	;   s(redo, Goal)
	). 

    s(Port, Goal) :-
	\+ (
	    numbervars(Goal, 0, _),
	    write(Port), write(': '), print(Goal), nl
	).

?- p(member(X, [1,2,3])), X = 3.
call: member(A, [1, 2, 3])
exit: member(1, [1, 2, 3])
redo: member(1, [1, 2, 3])
exit: member(2, [1, 2, 3])
redo: member(2, [1, 2, 3])
exit: member(3, [1, 2, 3])

X = 3 ;
redo: member(3, [1, 2, 3])
fail: member(A, [1, 2, 3])

No

Now is it clear why there is no "extra iteration" here?

	-------------------------------------------------------------------
	?- member(X,[1,2,3]) ,p( write('whee\!\!\!\n') ),X=3.
	-------------------------------------------------------------------
	(call) getting oldest item in que
	write('whee!!!\n')
	whee!!!
	(exit)
	(redo) putting that oldest back in as newest
	(fail) putting back as oldest in que
	(call) getting oldest item in que
	write('whee!!!\n')
	whee!!!
	(exit)
	(redo) putting that oldest back in as newest
	(fail) putting back as oldest in que
	(call) getting oldest item in que
	write('whee!!!\n')
	whee!!!
	(exit)
	X = 3
	Yes
	
	Comment: Close (but one extra subiteration)
	
But what is it that you think is an "extra subiteration"?
Once again, in this example, the ports that are visited are *precisely*
the ports that *have* to be visited in the four-port model.
In the four-port model, the events are

	call,(exit,redo)*,fail

With a more general model, one might have

	call,(exit,redo)*,(deterministic_exit|exit,cut|fail)

where deterministic exit means that the choice point is not kept
around any more, so the final redo,fail will be omitted, and
cut happens later, outside the goal in question, again removing
the choice point so that the final redo,fail will be omitted.

In order to support a customer's database connection scheme,
Quintus had to put in a special 'trail hook' so that clean-up
actions could be relied on even after determine exit or
subsequent cuts.  It also handled exceptions.
(I have never quite forgiven Quintus.  They never did pay me for
my shares when they were sold, and they yanked my paper on exception
handling from a conference, so that someone else got the credit for an
admittedly independent invention of it.  Nor have I forgiven the BSI
for ignoring the exception handling proposal I sent them at the end
of 1984; the so-and-sos never even gave it a document number.)