Prolog Operators

Prolog Lists

Built-In Predicates

Miscellaneous

Prolog - Collecting all solutions Predicates



We often need to generate all of the solutions to some goal within a program. There are three built-in predicates that can help us to get the results. These predicates are known as Colleting All Solutions Predictates as follows −

Predicate Description
findall/3 This predicate is used to make a list of all solutions X, from the predicate P.
setoff/3 Similar to findall/3, but it removes all of the duplicate outputs, and the returns the sorted answers.
bagof/3 Similar to setoff/3, but duplicates are retained, and the answers may not be sorted.

These three predicates take three arguments, so we have written /3 after the name of the predicates.

These are also known as meta-predicates. These are used to manipulate Prolog's Proof strategy.

These three predicates a list of all objects X, such that the goal P is satisfied (example: age(X,Age)). They all repeatedly call the goal P, by instantiating variable X within P and adding it to the list L. This stops when there is no more solution.

The findall/3 Predicate

This predicate is used to make a list of all solutions X, from the predicate P. The returned list will be L. So we will read this as find all of the Xs, such that X is a solution of predicate P and put the list of results in L. Here this predicate stores the results in the same order, in which Prolog finds them. And if there are duplicate solutions, then all will come into the resultant list, and if there is infinite solution, then the process will never terminate.

Now we can also do some advancement on them. The second argument, which is the goal, that might be a compound goal. Then the syntax will be as findall(X, (Predicate on X, other goal), L)

And also the first argument can be a term of any complexity. So let us see the examples of these few rules, and check the output.

Example

| ?- findall(X, member(X, [1,2,3,4]), Results).

Results = [1,2,3,4]

yes
| ?- findall(X, (member(X, [1,2,3,4]), X > 2), Results).

Results = [3,4]

yes
| ?- findall(X/Y, (member(X,[1,2,3,4]), Y is X * X), Results).

Results = [1/1,2/4,3/9,4/16]

yes
| ?- 

The setof/3 Predicate

The setof/3 is also like findall/3, but here it removes all of the duplicate outputs, and the answers will be sorted.

If any variable is used in the goal, then that will not appear in the first argument, setof/3 will return a separate result for each possible instantiation of that variable.

Let us see one example to understand this setof/3. Suppose we have a knowledge base as shown below −

kb4.pl

age(peter, 7).
age(ann, 5).
age(pat, 8).
age(tom, 5).
age(ann, 5).

Here we can see that age(ann, 5) has two entries in the knowledge base. And the ages are not sorted, and names are not sorted lexicographically in this case. Now let us see one example of setof/3 usage.

Example

| ?- consult('D:/TP Prolog/Sample Codes/kb4.pl').
compiling D:/TP Prolog/Sample Codes/kb4.pl for byte code...
D:/TP Prolog/Sample Codes/kb4.pl compiled, 4 lines read - 582 bytes written, 5 ms

yes
| ?- setof(Child, age(Child,Age),Results).

Age = 5
Results = [ann,tom] ? ;

Age = 7
Results = [peter] ? ;

Age = 8
Results = [pat]

(16 ms) yes
| ?- 

Here we can see the ages and the names both are coming sorted. For age 5, there is two entries, so the predicate has created one list corresponding to the age value, with two elements. And the duplicate entry is present only once.

We can use the nested call of setof/3, to collect together the individual results. We will see another example, where the first argument will be Age/Children. As the second argument, it will take another setof like before. So this will return a list of (age/Children) pair. Let us see this in the prolog execution −

Example

| ?- setof(Age/Children, setof(Child,age(Child,Age), Children), AllResults).

AllResults = [5/[ann,tom],7/[peter],8/[pat]]

yes
| ?- 

Now if we do not care about a variable that does not appear in the first argument, then we can use the following example −

Example

| ?- setof(Child, Age^age(Child,Age), Results).

Results = [ann,pat,peter,tom]

(15 ms) yes
| ?- 

Here we are using the upper caret symbol (^), this indicates that the Age is not in the first argument. So we will read this as, Find the set of all children, such that the child has an Age (whatever it may be), and put the result in Results.

The bagof/3 Predicate

The bagof/3 is like setof/3, but here it does not remove the duplicate outputs, and the answers may not be sorted.

Let us see one example to understand this bagof/3. Suppose we have a knowledge base as follows −

kb4.pl

age(peter, 7).
age(ann, 5).
age(pat, 8).
age(tom, 5).
age(ann, 5).

Example

| ?- bagof(Child, age(Child,Age),Results).

Age = 5
Results = [ann,tom,ann] ? ;

Age = 7
Results = [peter] ? ;

Age = 8
Results = [pat]

yes
| ?- 

Here for the Age value 5, the results are [ann, tom, ann]. So the answers are not sorted, and duplicate entries are not removed, so we have got two ann values.

The bagof/3 is different from findall/3, as this generates separate results for all the variables in the goal that do not appear in the first argument. We will see this using an example below −

Example

| ?- findall(Child, age(Child,Age),Results).

Results = [peter,ann,pat,tom,ann]

yes
| ?- 
Advertisements