1
votes

If I have some facts about how much money people own

% poor people
owns(luke,1).
owns(maria,3).
owns(sara,5).
owns(mike,9).

% rich people
owns(barbara,10).
owns(paula,11).
owns(thierry,19).

and a predicate isRich (returns true if a person P owns 10 or more)

isRich(P) :-
    owns(P,M),
    M >= 10.

I can call isRich(X) and I will get all bindings for X where X is a rich person, i.e.

?- isRich(X).
X = barbara ;
X = paula ;
X = thierry.

Now I want to have a predicate isPoor which is the inverse of isRich, i.e. it returns all bindings for poor people (people who own less than 10). Of course, I could write:

isPoor(P) :-
    owns(P,M),
    M < 10.

However, I want to write isPoor by calling isRich. Thus, when I change the predicate isRich (assume isRich is a more complex predicate) I don't have to change isPoor. Ideally, I would want to write something like:

isPoor(P) :-
    not(isRich(P)).

But when I call isPoor(X) as is defined above, I just get false instead of getting all possible bindings for X where X is a poor person:

?- isPoor(X).
false.

What I want is:

?- isPoor(X).
X = luke ;
X = maria ;
X = sara ;
X = mike.

Is there a way in SWI Prolog to call the inverse of a predicate such that it binds all possible variables?

1
You can enumerate the ppl and then call isRich/1 as in isPoor(P) :- owns(P,_), \+ isRich(P). - Tomas By
Thank you, @TomasBy! I posted your solution as an answer. - chris

1 Answers

1
votes

As Thomas By suggested, this does the trick:

% enumerate all people and
% return the ones that aren't rich
isPoor(P) :-
    owns(P,_),
    \+ isRich(P).