### 11.2.2 `bagof/3`

The `findall/3` predicate is useful, but in certain respects it is rather crude. For example, suppose we pose the query

`findall(Child,descend(Mother,Child),List).`

We get the response

`Child = _6947  Mother = _6951  List = [charlotte,caroline,laura,rose,caroline,laura,rose,laura,rose,rose] `

Now, this is correct, but sometimes it would be useful if we had a separate list for each of the different instantiations of `Mother`.

This is what `bagof` lets us do. If we pose the query

`bagof(Child,descend(Mother,Child),List).`

we get the response

`Child = _7736  Mother = caroline  List = [laura,rose] ; Child = _7736  Mother = charlotte  List = [caroline,laura,rose] ; Child = _7736  Mother = laura  List = [rose] ; Child = _7736  Mother = martha  List = [charlotte,caroline,laura,rose] ; no`

That is, `bagof` is more finegrained than `findall`, it gives us the opportunity to extract the information we want in a more structured way. Moreover, `bagof` can also do the same job as `findall`, with the help of a special piece of syntax. If we pose the query

`bagof(Child,Mother ^ descend(Mother,Child),List).`

This says: give me a list of all the values of `Child` such that `descend(Mother,Child)`, and put the result in a list, but don't worry about generating a separate list for each value of `Mother`. So posing this query yields:

`Child = _7870  Mother = _7874  List = [charlotte,caroline,laura,rose,caroline,laura,rose,laura,rose,rose]`

Note that this is exactly the response that `findall` would have given us. Still, if this is the kind of query you want to make (and it often is) it's simpler to use `findall`, because then you don't have to bother explicitly write down the conditions using `^`.

Further, there is one important difference between `findall` and `bagof`, and that is that `bagof` fails if the goal that's specified in its second argument is not satisfied (remember, that `findall` returns the empty list in such a case). So the query `bagof(X,descend(mary,X),Z)` yields `no`.

One final remark. Consider again the query

`bagof(Child,descend(Mother,Child),List).`

As we saw above, this has four solutions. But, once again, Prolog generates them one by one. Wouldn't it be nice if we could collect them all into one list?

And, of course, we can. The simplest way is to use `findall`. The query

`findall(List,bagof(Child,descend(Mother,Child),List),Z).`

collects all of `bagof`'s responses into one list:

`List = _8293  Child = _8297  Mother = _8301  Z = [[laura,rose],[caroline,laura,rose],[rose],                  [charlotte,caroline,laura,rose]] `

Another way to do it is with `bagof`:

`bagof(List,Child ^ Mother ^ bagof(Child,descend(Mother,Child),List),Z). List = _2648  Child = _2652  Mother = _2655  Z = [[laura,rose],[caroline,laura,rose],[rose],                  [charlotte,caroline,laura,rose]]`

Now, this may not be the sort of thing you need to do very often, but it does show the flexibility and power offered by these predicates.

Patrick Blackburn, Johan Bos and Kristina Striegnitz
Version 1.2.5 (20030212)