Search code examples
prologuniversalquantifiers

How to findall for universal facts in prolog?


In Prolog I can write

 child(martha,charlotte). 
 child(charlotte,caroline). 
 child(caroline,laura). 
 child(laura,rose). 

 descend(X,Y)  :-
    child(X,Y).
 descend(X,Y)  :-
    child(X,Z), 
    descend(Z,Y).

And then write

?-  findall(X,descend(martha,X),Z).

and get four solutions

Z  =  [charlotte,caroline,laura,rose]

But if I then add an universal fact

likes(X,pomegranate).

and try

 ?-  findall(X,likes(X, pomegranate),Z).

I get:

 Z = [_G17].

What is that _G17? What do I need to change to get essentially all variables? ( since likes(X,pomegranate) should mean everything likes pomegranate... right?) :

Z  =  [martha,charlotte,caroline,laura,rose]

Solution

  • Two solutions. The clean solution is to have a table that lists all "things" in the universe you describe:

    person(martha).
    person(charlotte).
    % etc
    

    And then your "likes" would be rather:

    person_likes(P, pomegranate) :-
        person(P).
    

    You can also try to hack around it:

    person(P) :- child(P, _).
    person(P) :- child(_, P).
    

    But this is... unsatisfactory? Think about a relational database: you would have two tables:

    CREATE TABLE person (
      id INTEGER PRIMARY KEY, -- usually autogenerated
      name TEXT NOT NULL
    );
    CREATE TABLE parent_child (
      parent_id INTEGER NOT NULL,
      child_id INTEGER NOT NULL,
      FOREIGN KEY parent_id REFERENCES person(id),
      FOREIGN KEY child_id REFERENCES person(id)
    );
    

    The only reason, as far as I am aware, why you don't do the exact same thing in Prolog, is that most introductory tutorials are trying to seduce you and avoid going into such details. And of course the Prolog "database" is not a true relational database (for example, argument position does matter!).

    TL;DR You can't avoid thinking about Prolog's resolution strategy when using Prolog.