[comp.lang.prolog] Four-Port Debugger

micha@ecrcvax.UUCP (Micha Meier) (09/22/88)

In article <264@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
>What I'm getting at is this: suppose I have a predicate
>	p(~~) :- q(~~), r(~~).
>and in a particular case q(~~) succeeds, but delivers the wrong answer,
>so that r(~~) fails.  We see something like this:
>	CALL p(~~) c	% creep
>	CALL q(~~) s	% skip
>	EXIT q(~~) c	% creep
>	CALL r(~~) s	% skip
>	FAIL r(~~) c	% oh dear, creep back to previous goal
>	REDO q(~~) r	% retry q
>	~a message saying that the debugger is going to retry~
>	CALL q(~~) s	% now creep into q
>
>Since I take pains to make my code determinate whenever that is appropriate,
>if the REDO port did not appear on q, I would have lost a large chunk of my
>tree and would have to spend several painful minutes reconstructing it.

	What you write is true, but it's only a part of the
	whole story:

		- first, when your goal q(~~) succeeds yielding wrong answer,
		  you normally see it immediately and retry it before
		  creeping to the next goal

		- if you happen to miss the wrong result, and creep to the
		  next goal and see it failing, there is nothing that can
		  prevent you from using retry <n> to retry q(~~) without
		  having to use the REDO port

		- if your clause was p(~~) :- q(~~), r(~~), s(~~), ...
		  and q(~~) gives wrong results but r and s do not
		  fail, you cannot use the REDO port to retry at all,
		  unless you want to spend several painful seconds creeping
		  to a FAIL port, if there is any, and then back to the REDO :-)
		  I'm almost sure you wouldn't do that, you would use retry <n>
		  instead, so why couldn't you do the same when it fails?

	Before proceeding further, I must say that the idea of a four-port
	debugger is ingenuous and it is not easy to think about an alternative.
	However, in some cases it might be quite difficult to understand
	from the trace what is going on in the Prolog system.
	As long as there is no failure, everything's ok, I can see the
	entry and exit of each procedure. What I find confusing is that
	when a goal fails, the debugger starts to repeat what he's already
	done, i.e. printing REDO ports where previously there were
	CALLs and EXITs, and he starts to do this from the top and not
	from the bottom, which is what one would expect from a depth-first
	search. In a clause
		p :- q, r, s, t.
	when t/0 fails and the most recent alternative is for q/0,
	the four-port debugger first REDOes s/0, then all its children,
	then r/0 and its children etc.

	   What I would expect from the debugger is that if a goal
	fails, he will print me a REDO of the goal which he *really*
	can redo, i.e. either one of the left-hand brothers or
	the nearest ancestor which or whose child have some alternative
	clauses to try. Maybe all this is just a confusion caused by
	the name REDO - the debugger is not really redoing what he says
	he is.

	   The above may be overcome, as Mr. Richard A. O'Keefe says,
	using another option in the debugger which shows directly
	the most recent choice point, although sometimes it might
	be more desirable to show the above mentioned brother or
	ancestor. But the fact that the debugger does not show
	a redo of the ancestor alternative clause is more serious,
	e.g. in
		p :- q, r.
		p :- s.

		q.

		r :- fail.

		s.

	the trace is
		| ?- p.
		   (1) 0 Call: p ? 
		   (2) 1 Call: q ? 
		   (2) 1 Exit: q ? 
		   (3) 1 Call: r ? 
		   (3) 1 Fail: r ? 
		   (2) 1 Redo: q ? 
		   (2) 1 Fail: q ? 
		   (4) 1 Call: s ? 	<=====
		   (4) 1 Exit: s ? 
		   (1) 0 Exit: p ? 

	At the marked place there is of course no REDO of p/0, since p/0
	has not yet been exited. However, I always find it confusing
	to see a goal failing and then immediately a call of another
	goal without any intermediate message. Clearly, saying
	RETRY p at this place is not possible when we want to have
	each port being either entry or exit and match the two,
	on the other hand, it is exactly what the system is doing there,
	he is re-trying to satisfy p/0 by selecting the second clause.

	   The box model is procedure-oriented, but normally the user
	is interested about clauses as well. The CALL and FAIL ports
	are related to the procedure, but the EXIT and REDO
	(taking redo literally, i.e. re-doing a call) are related
	to the clause.

	   I'd be interested in the experiences of other people
	with the four-port debuggers, is everybody completely
	satisifed with them?

--Micha