Some Useful Built-in Predicates

true always succeeds

fail always fails

repeat


Negation by Failure

\+ tests if its argument fails as a query Example
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:

clever(X):-
    \+(stupid(X)).

------------------------------------------------------------
?- clever(geoff).
yes
then add the fact stupid(geoff).
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:

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.

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

Tutorial

  1. Write difference_member(Element,Allowed,NotAllowed) which finds/checks for Elements that are members of the list Allowed but not members of the list NotAllowed.
    Answer
  2. Write xor_member(Element,List1,List2) which checks if Element is a member of only one of List1 and List2.


The Cut

The cut is a mechanism for indicating that certain predicates will not have (you do not want them to have) any other solutions.

Example

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
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: Example : cut implementing if-then-else
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

The problems with the cut is that the declarative meaning of the program may be changed:
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.

Tutorial

  1. If an animal has good camoflague and can keep still, then it always tries to hide (rather than run or fly) from a predator. If an animal hides, then it survives if the predator fails to have good eyesight and fails to have a good sense of smell. Otherwise it survives if it can run fast or if it can fly. Panthers run fast and have good eye sight. Cheetahs run fast, have good eye sight, and a good sense of smell. Rabbits have good camoflague and can keep still. Deer can keep still and can run fast. Tortoises can keep still. Hawks have good eye sight and can fly. Lemmings have good camoflague, can keep still, can run fast, and can fly (off a cliff). None of these animals are cannibalistic.

    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)] 
Answer


Disjunction

; 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".

-> is used for if-then

-> ; is used for if-then-else