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).
yes
then add the fact stupid(geoff). (NonMonoMore)
clever(X):-
\+(stupid(X)).
stupid(geoff).
------------------------------------------------------------
?- clever(geoff).
no
The 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).
no
The 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
yes
but (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
yes
This 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.