I'm in Prolog and i have this fact:
likes(mary,juice).
I want to put a cut after this fact
likes(mary,juice),!.
But the Prolog compiler doesn't allow me to do that. Why it's uncorrect ? ( I want to prevent backtracking after this fact is chosen)
As a comment suggested, you have to turn the fact into a rule put the cut into the rule's body:
likes(mary, juice) :-
!.
(The usual warnings about cut apply. It can change your program's meaning in ways you don't expect and should be avoided unless you know exactly what you're doing and you really need the speedup it provides.)
Related
In conversations around Prolog's cut operator !/0, I have only ever heard it described in terms of choice points and Prolog's execution model. It also seems to me that cut was introduced to give more "imperative" control over the search procedure, and to potentially improve the performance of some programs, but not so much for theoretical reasons. For examples of such discussions, see SWI Prolog's documentation, SICStus Prolog's documentation, and the Wikipedia article on cuts.
I'm curious if there are other ways of thinking about cuts in Prolog code? Specifically, can cut be given (possibly messy) declarative semantics in the language of first order logic? Second order logic? Higher order logic? If not, are there extensions to these logics that make it possible to implement cut?
There is no declarative semantics for the cut in the general case. It suffices to consider one counterexample:
?- X = 2, ( X = 1 ; X = 2 ), !.
X = 2.
?- ( X = 1 ; X = 2 ), !, X = 2.
false.
So once it is the case and once not. Therefore, conjunction is not commutative. But to have a declarative semantics, conjunction must be commutative. And even in Pure Prolog commutativity of conjunction holds1. So maybe there is some way to twist the meaning of declarative. But twisting it that far is just too much.
The only statement we can say is that in a program with cuts the search space is somehow pruned compared to the very same program without cuts. But usually that is not that interesting. Think of Prolog negation.
mynot(G_0) :-
G_0,
!,
false.
mynot(_G_0).
So this is compared to its cut free version where the fact will always ensure success. The meaning of negation is therefore lost in the cut free program.
However, some uses of cuts do have a declarative semantics. But those cuts are typically guarded to ensure that it does not cut too often. These guards may come in different styles. One possibility is to produce an instantiation error in case the arguments are not sufficiently instantiated. Another is to fail and resort to the original definition. Another is to ensure that arguments are sufficiently instantiated by some mode system. As long as such mode system is actually enforced it is a declarative option. However, if modes are only commentary decorum, the declarative meaning is lost.
1 Conjunction in Pure Prolog is commutative modulo termination and errors.
"Purely for performance"?
Cuts are convenient, as a sometimes-more-elegant alternative to if-then-else.
I'm new to prolog, and am experimenting with how to get it to stop querying after it finds one answer. I'm using this code:
member1(L,[L|_]).
member1(L,[_|RS]) :- member1(L,RS),!.
The result is:
| ?- member1(3,[3,2,3]).
true ? a
yes
I'm lost as to how I could get Prolog to stop printing "true ?" and just print "yes" instead. I've tried using if/else construct and the format function but it still prints "true ?". Any ideas?
You're cutting the wrong place. Cut after the base condition, which says, "once the base is met, don't backtrack any more":
member1(L,[L|_]) :- !.
member1(L,[_|RS]) :- member1(L,RS).
If-then does work for me, perhaps you implemented it different? (on swi-prolog)
member1(X,[Y|RS]) :-
( X = Y -> true
; member1(X,RS) -> true
; false
) .
Swi also has the predicate once/1.
edited to account for the error pointed out by false.
From the output you show, I assume you are using GNU Prolog. But, first just an important remark:
The cut you placed does not cut as you intend it! In fact, it does not even prevent that there is a single answer. Here is evidence for that:
| ?- member1(X,[1,2,3]).
X = 1 ? ;
X = 2
yes
So you still have two answers. As a rule of thumb: a cut after a recursive goal often does some unexpected things.
If you insist to have exactly the first answer, simply say once(member(X,[1,2,3])). The once/1 is effectively a cut, too, but quite in disguise. It is tamed to do exactly one thing. Yes, you can place also cuts into recursive rules, but for a beginner, better leave that to a later lesson.
Behind all this there is another point, which is less visible: The toplevel shell of GNU Prolog will ask you for further solutions if it sees an open alternative (jargon: choicepoint). So when GNU asks you for more, it knows that some part has yet to be explored, but there is no guarantee, that there is actually another answer:
?- member(1-X,[1-a,2-b,3-c]).
X = a ? ;
no
Here, the toplevel sees an open choicepoint and thus asks if you want to explore the query any further. Alas, this search is in vein...
I've took a course in which I learned some prolog. I couldn't figure out how / when to use cuts. Even though I get the general idea of cuts, I can't seem to use them properly.
Can anyone explain it briefly or give a good tutorial (that's not learnprolognow.org) on "cuts" that they can recommend?
TL;DR: Don't.
The cut prunes Prolog's search tree. That is, given a pure Prolog program without cut and the same program with cuts the only difference is that the program with cuts might spend less time in fruitless branches, and thus is more efficient ; might have fewer answers ; it might also terminate whereas the original program doesn't.
Sounds pretty harmless ... or even useful, doesn't it?
Well, most of the time things are more complex.
Red cuts
Cuts are often used in a way such that the program without cuts has no sensible meaning at all. Such cuts are called red cuts. In the better cases it is used to implement a crude form of non-monotonic negation. And in some other cases it is half negation, half some procedural meaning that is very difficult to understand. Not only for the reader of the program but also for its writer. In fact, often such uses unintentionally lack steadfastness. In any case: these cuts are not placed into an existing program. They are meant to be in that program right from the beginning.
For the more structured uses of such red cuts, better use once/1, (\+)/1, or (;)/2 – if-then-else like ( If -> Then ; Else ) instead. Even better, try to guard such constructs against unintended uses by issuing instantiation_errors. Or use iwhen/2 which produces instantiation errors or when/2 (offered in SWI, YAP, SICStus) which delays goals.
Green cuts
Cuts that remove useless choicepoints (and also redundant answers) are called green cuts. But beware: You cannot place them into your program simply pressing ! and some #00ff00. Most of the time you need a clean read-only guard to ensure that there is no way this cut turns #ff0000. There is also a simple way to remove some leftover choicepoints safely: call_semidet/1. Here are some related cases:
What's the SLD tree for this query?
Prolog append with cut operator
What are the optimal green cuts for successor arithmetics sum?
Implementing "last" in Prolog
Cut is not commit
Finally, let me point out that cut is not a commit-operator. It sometimes acts a bit like it, but would need lots of restrictions to be one. A commit-operator cannot be (ab)used to implement (\+)/1. A commit requires that each clause is tried independently of each other. Each clause thus needs a full guard ; it cannot rely on being tried only after some other clauses have been tried first. Also, a commit would have to occur in each clause of a predicate. The cut can occur anywhere.
A cut commits the Prolog goal being proved to the choices done.
It must be used then when the programmer knows that any alternative available must not be tried.
The most prominent use it's the implementation of negation by failure.
fact(a).
fact(b).
/* 1 */ neg(X) :- call(X), !, fail.
/* 2 */ neg(_).
Here I've (re)defined the standard negation operator, normally it's (\+)/1
?- neg(fact(c)).
true.
call(fact(c)) by rule 1 can't be proved, and the alternative rule 2 then succeeds.
?- neg(fact(a)).
false.
because fact(a) can be proved, the cut discard the alternative before failing.
?- neg(fact(X)).
false.
there exist at least an unknown X such that fact(X) succeed.
?- neg(neg(fact(X))).
true.
the double negation has the effect that variables don't get bound. This can be useful when doing meta programming, to fetch clauses without altering their 'structure'. From the operational viewpoint, it's clear (?) what's going on, but the program does lose its declarative property.
Another use, useful only in rudimentary interpreters, was to instruct the system to perform last call optimization, prefixing the recursive call with a cut. Then the system can avoid to allocate the stack space normally required to keep track of alternative point. A dummy example:
print_list([E|Es]) :- print_element(E), !, print_list(Es).
print_list([]).
edit about a tutorial: I found that 'Clause and Effect' by William Clocksin contains a detailed survey related to cut: chapter 4 'Choice and Commitment' it's fully devoted to cut pros and cons. At bottom line, mainly cons...
Before using a cut, I require that my predicates meet these two criteria:
it gives correct answers without a cut
it gives correct answers if clauses are reordered
Once my predicate behaves that way, I sometimes add a cut to trim away unwanted nondeterminism.
For example, a predicate to test whether a number is positive, negative or zero.
sign(N, positive) :-
N > 0.
sign(N, negative) :-
N < 0.
sign(N, zero) :-
N =:= 0.
Each clause stands completely independent of the others. I can reorder these clauses or remove a clause and the remaining clauses still give the expected answer. In this case, I might put a cut at the end of the positive and negative clauses just to tell the Prolog system that it won't find any more solutions by examining the other clauses.
One could write a similar predicate without cut by using -> ;, but some dislike how it looks:
sign(N, Sign) :-
( N > 0 -> Sign=positive
; N < 0 -> Sign=negative
; Sign=zero
).
Cuts all but disappeared from my code once I found the once predicate. Internally it acts like
once(X) :- X, !.
and I found it very useful for making a firm decision on how to do something before I did that something.
For example, here is my standard meta-interpreter. The maybe1/1 clause has unique functors in its arguments so once they known, then the right maybe1/1 can be selected, perfectly.
The job of finding that unique function is given to the maybe0/2 pre-processor that sets Y to a "what to do statement" about X.
Without once, this could would have to be riddled with cuts. E.g. in maybe1, there are three/two different interpretations of X/Y,and or that we need to check in a top down manner. But check it out- no cuts.
maybe(X) :-
once(maybe0(X,Y)), maybe1(Y).
maybe0(true, true).
maybe0((X,Y), (X,Y)).
maybe0((X;Y), or(L)) :- o2l((X;Y),L).
maybe0(X, calls(X)) :- calls(X).
maybe0(X/Y, fact(X/Y)) :- clause(X/_, true).
maybe0(X/Y, rule(X/Y)) :- clause(X/_,_).
maybe0(X/Y, abducible(X/Y)).
maybe0(or([H|T]), or([H|T])).
maybe0(or([]), true).
maybe1(true).
maybe1((X,Y)) :- maybe(X),maybe(Y).
maybe1((X;Y)) :- maybe(X);maybe(Y).
maybe1(abducible(X)) :- assume(X,0).
maybe1(fact(X)) :- assume(X,1), one(X).
maybe1(rule(X)) :- assume(X,2), one(clause(X,Y)), maybe(Y).
maybe1(calls(X)) :- one(clause(X,Y)), maybe(Y).
maybe1(or([H|T])) :- any(One,Rest,[H|T]), ignore(maybe(One)), maybe(or(Rest)).
Cut predicate prevents backtracking.Cut predicate is specified as an exclamation point (!). Cut prunes the search tree and shortens the path track by prolog interpreter.Semantically it always succeed.
read(a).
read(b).
color(p, red) :- red(p).
color(p,black) :- black(p),!.
color(p,unknown).
?-color(X,Y).
X = a,
Y = red;
X = b,
Y = black;
Without cut the goals shows Y=unknown after Y=black.
There are two types of cut predicate :
Green Cut : Green cut is one type of cut which had no effect on the declarative meaning. It is only use to improve efficiency as well as avoid unnecessary computation. The removal of green cut from the program does not changes the meaning of the program.
Red Cut : Red cut is one which had effect on the the declarative meaning. The removal of red cut from the program changes the meaning of the program.
pred(Args).
pred(Args) :-
goalA,
goalB,
!,
pred(Args).
pred(Args) :-
goalC,
goalD,
!,
pred(Args).
Normally I would write a recursive predicate that was concerned with memory performance something along the lines of the above snippet of code. With the cut being used to try to force tail call optimization to occur. I have recently been going through a large prolog code base and have found some examples where the cut is actually after the recursive call rather than immediately before it. Presumably this has the effect of preventing tail call optimization from happening rather than assisting it.
My question is can I move the cut from after the recursive call to immediately prior to it without affecting the meaning of the program? This is assuming that there is a cut in the same relative location for each clause of the predicate.
Now I've been thinking about it some more, I'm thinking maybe the answer is "not necessarily", but having rewritten all the code with the cut before the call and finding that the test suite is still passing, I'm also wondering if there might be some other esoteric reason for writing predicates like this. Or is it just bad coding?
My guess is that it might be bad coding (or misunderstanding what author was doing)
I'm saying this, because I, myself, did once the same error:
https://mailbox.iai.uni-bonn.de/mailman/public/swi-prolog/2009/001540.html
http://xonix.habrahabr.ru/blog/60430/ (warning, in russian)
But people from SWI mailing-list confirmed that right way of tail-recursive code is
head :-
<guard goals>, !,
<deterministic stuff>,
head.
head :-
...
I have a question I would like to ask you something about a code snippet:
insert_pq(State, [], [State]) :- !.
insert_pq(State, [H|Tail], [State, H|Tail]) :-
precedes(State, H).
insert_pq(State, [H|T], [H|Tnew]) :-
insert_pq(State, T, Tnew).
precedes(X, Y) :- X < Y. % < needs to be defined depending on problem
the function quite clearly adds an item to a priority queue. The problem I have is the cut off operator in the first line. Presumably whenever the call reaches this line of code this is the only possible solution to the query, and the function calls would simply unwind (or is it wind up?), there would be no need to back track and search for another solution to the query.
So this cut off here is superfluous. Am I correct in my deduction?
Yes, any half-decent Prolog compiler will notice that there is no other clause where the second argument is an empty list.
It would be more useful at the end of the second clause, though I'd rather combine the second and the third clause and use a local cut (precedes(...) -> ... ; ...).
The particular technique that the compiler users to eliminate candidate predicates for matching is called argument indexing. Different prolog implementations could potentially index different numbers of arguments by default.
So if you're worried about whether an argument is being indexed or not, you should check how many arguments the prolog you're using indexes. According to the SWI reference manual it only indexes the first argument by default. So in your case the cut is actually not redundant. You can however explicitly stipulate which arguments should be indexed using the predicates index/1 and hash/1 which are linked to in the above link.
Or you could just reorder the arguments, or you could just keep the cut.
Yes, you are correct. Even if the compiler isn't half-decent (which SWI Prolog certainly is), the worst it can do is match the second and third clauses, which will fail immediately.
However, if the second clause matches, the third does as well. Is this the intended behaviour?