Justin
Justin

Reputation: 13

Prolog: Give list to a fact

Lets say I'm looking for someones friends.

friend(mary, peter).
friend(mary, paul).
friend(mary, john).
friend(mary, justin).

friend(chris, peter).
friend(chris, paul).
friend(chris, conner).
friend(chris, louis).

friend(tyler, justin).
friend(tyler, lindsey).
friend(tyler, frank).
friend(tyler, paul).

friend(dan, justin).
friend(dan, conner).
friend(dan, frank).
friend(dan, peter).

In the above example I know that I can do something like

friend(X, paul).

which will tell me everyone paul is friends with

or also

findall(X, friend(X, paul), L).

which will return a list of everyone paul is friends with.

Let's say that I want to go a little bit deeper in my search and refine it. So let's say that I was to do

findall(X, friend(X, paul), A).

To get A to be a list of [mary, chris, tyler]. But then I wanted to further refine that search. I want to be able to put the list into the function (I know this isnt valid but this is my thought pattern for what I want to do) for something like

findall(A, friend(A, peter), B).

To get back just [mary, chris] this time. And then even FURTHER refine it to say

findall(B, friend(B, conner), C).

To finally conclude my search to find [chris]

Is this possible? Is there a better or even possible way to do this?

Upvotes: 1

Views: 69

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476503

Chain conditions

Given I understood it correctly, you want to generate a list of people that are friends with paul, peter and connor. We can do that by "constructing" a goal that aims to satisfy the three conditions:

findall(F, (friend(F, paul), friend(F, peter), friend(F, conner)), L).

or another conjunction of conditions. These then give:

?- findall(F, (friend(F, paul)), L).
L = [mary, chris, tyler].

?- findall(F, (friend(F, paul), friend(F, peter)), L).
L = [mary, chris].

?- findall(F, (friend(F, paul), friend(F, peter), friend(F, conner)), L).
L = [chris].

Filter an existing list with member/2 in the goal

Or we can also use two calls, and use member/2 to "emulate" an intersection like:

findall(F, friend(F, paul), L1),
findall(F, (member(F, L1), friend(F, peter)), L2).

here we thus use member/2 such that F2 only takes values from L1 (the result of the initial findall/3), but I think the first way is cleaner and more self explaining: we want after all a list of Fs that are friends with paul, and peter, and conner.

Using maplist/2 to obtain people that are friends with everybody in a list

We can also find the people that are friends with a list of people by using maplist/2 here:

findall(F, maplist(friend(F), [paul, peter, conner]), L).

Post-process with an intersection

We can also make two separate findall/3 calls, and then calculate the intersection:

findall(F, friend(F, paul), L1),
findall(F, friend(F, paul), L2),
intersection(L1, L2, M).

Here M will thus contain the elements that are both in L1 and L2. But a potential problem here is that the second predicate can generate a lot of results that were not possible with given we filtered with the values of the first predicate.

Upvotes: 1

Related Questions