Depending on faliure to prove in prolog

Viewed 29

Consider this code

:- use_module(library(clpfd)).
p(1).
p(3).
p(5).
p(7).

predecessor(A, B) :- A #= B - 1. % is true for pairs 

q(X) :- predecessor(P, X), \+ p(P).

If I query ?- p(X) I correctly get the results

?- p(X).
X = 1 ;
X = 3 ;
X = 5 ;
X = 7.

But if I query ?- q(X) then I get false. I realize that \+ is really not negation but faliure to prove, but what if not being able to prove something is sufficient for another predicate being true?

I wanted to give a reasonable use case / example which is why I resorted to using clpfd. Even without using it, I have another example which I can present:

likes(betty, butter).
likes(betty, jam) :- fail.

dislikes(betty, Item) :- \+ likes(betty, Item).

This example too, has a shortcoming that likes(betty, jam) :- fail. isn't really doing anything. But I hope I'm able to get my point across.

Is there a way in prolog to define this dependence?

1 Answers

You have to specifically define the "negative universe" of possibilities if you want Prolog to provide solutions in that space.

For instance, \+ p(X) cannot tell you specific values of X because the possible X that meet this criteria have not been defined. You're asking Prolog to invent what X might possibly be, which it cannot do.

You could define the universe of all possible values, then you can define what \+ p(X) means:

:- use_module(library(clpfd)).

p(1).
p(3).
p(5).
p(7).

predecessor(A, B) :- A #= B - 1. % is true for pairs 

q(X) :- predecessor(P, X), P in 0..9, label([P]), \+ p(P).

Then you get:

2 ?- q(X).
X = 1 ;
X = 3 ;
X = 5 ;
X = 7 ;
X = 9 ;
X = 10.

3 ?-

Here we've told Prolog that the possible universe of P to choose from is defined by P in 0..9. Then the call \+ p(P) can yield specific results. Unfortunately, using \+, you still have to apply label([P]) before testing \+ p(P), but you get the idea.

In your other example of likes, it's the same issue. You defined:

likes(betty, butter).
likes(betty, jam) :- fail.

As you indicated, you wouldn't normally include likes(betty, jam) :- fail. since failure would already occur due to lack of a successful fact or predicate. But your inclusion is really an initial attempt to define the universe of possible choices. Without that definition, Prolog cannot "invent" what to pick from to test for a dislike. So a more complete solution would be:

person(jim).
person(sally).
person(betty).
person(joe).

food(jam).
food(butter).
food(eggs).
food(bread).

likes(betty, butter).

Then you can write:

dislikes(Person, Food) :-
    person(Person),
    food(Food),
    \+ likes(Person, Food).
Related