true
always succeeds
fail
always fails
repeat
repeat. repeat:- repeat.
write_lots:- repeat, write('lots and '), fail.
get_option(Option,LegalOptions):- repeat, write('Prompt :'), read(Option), member(Option,LegalOptions).
\+
tests if its argument fails as a query
\+
is a prefix operator, and is declared as fx
.
\+
may only be used in the tail of a clause.
citizenship_approved(Person):- applicant(Person), \+ criminal(Person), qualified(Person). applicant(bin_laden). applicant(bill_clinton). applicant(groucho_marx). criminal(bin_laden). qualified(chris_skase). qualified(groucho_marx). ----------------------------------------------------------- ?- citizenship_approved(X). yes X = groucho_marx
The basis of negation by failure is the closed world assumption (CWA). The CWA is non-monotonic, i.e. the addition of new axioms may reduce the amount of information derivable. For example: (NonMonoBase)
clever(X):- \+(stupid(X)). ------------------------------------------------------------ ?- clever(geoff). yesthen add the fact stupid(geoff). (NonMonoMore)
clever(X):- \+(stupid(X)). stupid(geoff). ------------------------------------------------------------ ?- clever(geoff). noThe fact
clever(geoff)
is no longer derivable.
Negation by failure is not as powerful as the CWA. For example: (NotCWA)
s(a). q(b). q(X):- r(X). r(X):- q(X).The set of true things is
{ s(a),q(b),r(b) }
.
Thus under CWA not(q(a))
is true.
But negation by failure cannot find this as the search is infinite.
Negation by failure requires finite failure.
Non-ground negated goals. (NegateNonGround)
r(a). q(b). p(X):- \+(r(X)). ------------------------------------------------------------ ?- q(X),p(X). yes X = b. ?- p(X),q(X). noThe problem in the second query is that
X
is unbound in
\+(r(X))
.
In logic not(not(p))
is equivalent to p
.
Not true for \+
. For example:
p(a). ------------------------------------------------------------ ?- p(X). yes X = a. ?- \+(\+(p(X))). yes X = X.The problem is that the negated goal is non-ground.
Thus, for \+
to work
difference_member(Element,Allowed,NotAllowed)
which
finds/checks for Elements that are members of the list
Allowed
but not members of the list
NotAllowed
.
Example (MemberNoCut)
member_check(Element,List,winner):- member(Element,List), write('It is a member'), nl. member_check(_,_,loser):- write('It is not a member'), nl. ------------------------------------------------------------ ?- member_check(b,[a,b,c,d,b,b],X). It is a member X = winner More ? ; It is a member X = winner More ? ; It is a member X = winner More ? ; It is not a member X = loser yesbut (MemberCut)
member_check(Element,List,winner):- member(Element,List), !, write('It is a member'), nl. member_check(_,_,loser):- write('It is not a member'), nl. ------------------------------------------------------------ ?- member_check(b,[a,b,c,d,b,b],X). It is a member X = winner yesThis illustrates the first and second effects of the cut:
factorial(N,Answer):- N > 1, !, N1 is N - 1, factorial(N1,N1Answer), Answer is N * N1Answer, write('Calculated for '), write(N), nl. factorial(N,1):- write('Calculated for '), write(N), nl.
Advantages of using the cut
p:- a, b. p:- c.has meaning
p <=> (a & b) v c
, and the clause order is
irrelevant.
p:- a, !, b. p:- c.has meaning
p <=> (a & b) v (~a & c)
, and swapping clause
order is relevant.
p:- c. p:- a, !, b.has meaning
p <=> c v (a & b)
, thus necessitating dependance
on the procedural interpretation of Prolog.
Cuts that change the declarative meaning (red cuts) of a program should be avoided. Those that do not change the declarative meaning (green cuts) may be used.
Here is the entry point to a program that looks for predator-dinner pairs ...
eats(Predator,Dinner):- animal(Predator), animal(Dinner), Predator \== Dinner, \+ survive(Predator,Dinner).Write the survive and other procedures, so that a query:
?- findall(yummo(P,D),eats(P,D),Menu).returns:
Menu = [yummo(panther, rabbit), yummo(panther, tortoise), yummo(panther, lemming), yummo(cheetah, rabbit), yummo(cheetah, tortoise), yummo(cheetah, lemming), yummo(rabbit, tortoise), yummo(deer, tortoise), yummo(hawk, rabbit), yummo(hawk, tortoise), yummo(hawk, lemming), yummo(lemming, tortoise)]
;
is used for or
a:- b ; c.is read as "to satisfy a, satisfy either b or c" and declaratively as "a is true if either b or c is true".
,
binds stronger than ;
, so
a:- b, c ; d, e.is read as
a:- ( b, c ) ;( d, e).and is equivalent to
a:- b, c. a:- d, e.This method of writing is clearer and is definitely preferred.
->
is used for if-then
(
<condition> ->
<query>)
safe_divide(Numerator,Denominator,Quotient):- (Denominator \= 0 -> Quotient is Numerator / Denominator).
-> ;
is used for if-then-else
(
<condition> ->
<true query> ;
<false query>)
factorial(N,Answer):- (N > 1 -> ( N1 is N - 1, factorial(N1,N1Answer), Answer is N * N1Answer );( Answer = 1)), write('Calculated for '), write(N), nl.