Article View: comp.lang.prolog
Article #3556Re: The double-cut (long)
From: Jonas Nygren
Date: Mon, 08 Aug 1988 16:27
Date: Mon, 08 Aug 1988 16:27
160 lines
5237 bytes
5237 bytes
In a previous article I suggested a new language primitive for Prolog,
the double-cut with the following semantics:
a :- b, c, !!, d, e.
to achieve the equivalence of:
a :- b, c, !, d, !, e, !.
Below are most of the comments, in short, I recieved, followed by a
final comment from me where I try to state my case.
-------------
2 are there any Prolog-variants with similar functionality?
From: "Brad Miller" <miller@ACORN.CS.ROCHESTER.EDU>
>From the RHET user manual (tr 238, university of rochester)
\hornfnitem{And*}{$<$Form$>$*}{New\\Current Status: Untested} A macro form
for \HC{AND [CUT] Form1 [CUT] Form2 \ldots [CUT] FormN}. That is, any
backtracking\index{backtracking}\ needed at all inside of the AND* causes it
to fail.
------------------
From: Peter Reintjes <pbr@mcnc.org>
............ It is almost never
necessary -- no that is too mild -- it is never *necessary*
< -- to have more than one cut per clause -- >,
and you are right that it looks messy.
Richard O'Keefe has written a very good little paper on
the correct use of cuts. ..........
-----------
>From: ok@quintus.uucp (Richard A. O'Keefe)
Forgive me, but I cannot imagine this cropping up. Why do you WANT to
prevent backtracking over system-calls? You can backtrack over read/1,
write/1, var/1, assert/1 &c all you like, it doesn't hurt. As a general
rule, code with side-effects should be determinate, so backtracking over
it will do nothing at all. (retract/1 is an exception, but I doubt that
anyone would commend as an example to follow.)
Please let's see a real example of where you think you need to do this.
>> SEE example below!
----
>From: gooley@s.cs.uiuc.edu
Some debuggers on some systems (C-Prolog is one, I think) show apparent
retries of deterministic system calls. Might this be misleading people
into thinking that cuts are needed to prevent such retries in actual
execution?
---------
>From: lang@zeta.PRC.Unisys.COM (Francois-Michel Lang)
This could also be a "problem" for when debuggers show apparent
retries of deterministic user-defined predicates.
<-- examples -->
In the second example, it looks like the cut has saved some work,
whereas it really hasn't.
---------
My comments to the response :
Well somebody else have had the same thought (rochester above) before me and
I still have to wait for an original idea. The reason behind the double-cut
suggestion wasn't performance and it wasn't induced by trace or debug output.
Rather it was triggered by the code I had to construct in order to make my
program work correct.
Instead of inventing my own example I choose to base it on an example most of
you have seen, the reconsult example in Clocksin & Mellish. I have done some
smaller modifictions to the code. After this follows the same example
but with the use of the double-cut.
myreconsult(File) :-
retractall(done(_)),
assert(done(1)),
seeing(Old),
see(File),
repeat,
read(Term),
try(Term),
seen,
see(Old),
!.
try(X) :- is_eof, !.
try((?- ...Goals)) :- !, do_call(Goals), fail.
try(Clause) :-
head(Clause,Head),
record_done(Head),
assertz(Clause),
fail.
do_call([]) :- !.
do_call([G|Goals]) :- call(G), do_call(Goals), !.
record_done(Head) :- done(Head), !.
record_done(Head) :-
functor(Head,Func,Arity),
functor(Proc,Func,Arity),
asserta(done(Proc)),
retractall(Proc),
!.
head((A:-B), A) :- !.
head(A,A).
The cuts in 'do_call','record_done' and 'head' are due to the fail in 'try'
which means that the complexity of 'try' (2nd & 3rd clause) has propagated to
their subgoals. Using the doubel-cut as proposed would allow us to limit
the complexity to the clause where it arises:
dc_try(X) :- is_eof, !!. % Just for symmetry
dc_try((?- Goals)) :- !!, dc_do_call(Goals), fail.
dc_try(Clause) :- !!,
dc_head(Clause,Head),
dc_record_done(Head),
assertz(Clause),
fail.
dc_do_call([]).
dc_do_call([G|Goals]) :- call(G), dc_do_call(Goals).
dc_record_done(Head) :- done(Head).
dc_record_done(Head) :-
functor(Head,Func,Arity),
functor(Proc,Func,Arity),
asserta(done(Proc)),
retractall(Proc).
dc_head((A :- ...B), A).
dc_head(A,A).
In this code no cuts are needed in 'dc_do_call', 'dc_record_done' or
'dc_head' and the fail-complexity is totally contained in 'dc_try'.
Mr O'Keefe it's not a question of necessity but of beauty and functionality.
In the last example the number of cuts has actually diminished with use of
the double-cut and the code is 'cleaner' and easier to understand, I believe.
I don't know if I have been able to show how the double-cut could benefit
Prolog but I will not carry my 'campaign' further, this is my last entry on
the double-cut.
Jonas Nygren
Technical Details
Message-ID:
<1164@ttds.UUCP>Path:
arc1-ca.pugleaf.net!utzoo!utgpu!attcan!uunet!mcvax!enea!kth!draken!ttds!jonasnShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!attcan!uunet!mcvax!enea!kth!draken!ttds!jonasn From: jonasn@ttds.UUCP (Jonas Nygren) Newsgroups: comp.lang.prolog Subject: Re: The double-cut (long) Message-ID: <1164@ttds.UUCP> Date: 8 Aug 88 16:27:40 GMT Reply-To: jonasn@ttds.UUCP (Jonas Nygren) Organization: The Royal Inst. of Techn., Stockholm Lines: 160