<< Prev | - Up - | Next >> |
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.
<< Prev | - Up - | Next >> |