Path: 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 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" >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 ............ 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