2

How to create such logic in GNU Prolog? How to define not_a_parent() predicate?

parent(john,chris).
parent(mary,chris).
not_a_parent(X) :- \+ parent(X,Y).

The interesting answer to the similar question is What is the logical 'not' in Prolog?. But I do not see how to implement it here.

false
  • 10,264
  • 13
  • 101
  • 209
Kosarar
  • 151
  • 1
  • 9
  • See [Prolog get object or objects that do not complay a fact](https://stackoverflow.com/questions/42305191/prolog-get-object-or-objects-that-do-not-comply-a-fact/42305644#42305644) – lurker May 23 '17 at 14:05
  • Possible duplicate of [Prolog: Get object or objects that do not comply a fact](https://stackoverflow.com/questions/42305191/prolog-get-object-or-objects-that-do-not-comply-a-fact) – lurker May 23 '17 at 14:05

3 Answers3

1

You need to enumerate all the persons somehow. For example

not_a_parent(X) :- ( X = john ; X = mary ; X = chris ), \+ parent(X,_).

In any real program you would probably have some simple way to get all persons, and then you can do

not_a_parent(X) :- person(X), \+ parent(X,_).
Tomas By
  • 1,396
  • 1
  • 11
  • 23
1

This worked for me:

parent(john,chris).
parent(mary,chris).
parent(mary,suzanne).
parent(suzanne,jane).
parent(suzanne,peter).
parent(peter,rose).
parent(jerry,rose).
parent(jane,carl).

not_a_parent(NonParents) :- setof(Z,Y^parent(Y,Z),SetOfChildren),
           findNonParents(SetOfChildren, NonParents, []),!.

findNonParents([],A,A).

findNonParents([H|SetOfChildren], NonParents, A):-
        not(call(parent(H,_))),
        findNonParents(SetOfChildren,NonParents,[H|A]).

findNonParents([_|SetOfChildren], NonParents, A):-
        findNonParents(SetOfChildren,NonParents,A).

Result for querying not_a_parent(NonParents) is:

?- not_a_parent(NonParents).
NonParents = [rose, chris, carl].
Miruna Pislar
  • 126
  • 2
  • 3
  • Ah, I thought you wanted a list of all the people who are not a parent of a particular person X (e.g. john). I've edited the code, should be fine now. – Miruna Pislar May 25 '17 at 07:53
  • Small remark - no "not" is present in GNU Prolog, I use "\+" instead. Your method is very cool - without additional facts (like person(chris)), only with predicates. I learned to cut in a very intrinsic way! – Kosarar May 25 '17 at 10:31
0

You need to get all the instances of parent/2 such that X never unifies parent(X,_). findall(Template, Goal, Instances) executes the Goal until it fails and populate the list Instances with the terms that unify the Template. That way, if the list Instances is empty then parent(X,_) does not exist.

So your predicate would be like:

not_a_parent(X):- findall(_, parent(X,_) , []).
Manolo
  • 1,500
  • 1
  • 11
  • 15
  • findall/3 is part of gnu-prolog ( the tag you used in your question). In any case the principle of the solution is explained and that version of prolog should have something similar. So you can either look for an equivalent implementation of findall or develop your own (e.g. using retractall). – Manolo May 24 '17 at 20:10
  • findall/3 is present. GCL-2.6.7-ANSI Prolog IDE is GNU-Prolog. The result of the call of your function is No. Have you tested it? – Kosarar May 25 '17 at 10:15
  • Sure. https://www.dropbox.com/s/qwuqxsn4e6lcg5z/Screenshot_20170530_114552.png?dl=0 – Manolo May 30 '17 at 09:48
  • Great answer too. But I explained badly what I wanted. I wanted a list of all non-parents as an answer. But you gave an interesting result too. – Kosarar May 31 '17 at 11:27
  • Then rewrite your question. – Manolo May 31 '17 at 19:05