## Success if no solution

As the description says, unlike bagof/3 and setof/3, findall/3 succeeds with an empty `Bag`

if there are no solutions:

If we have the database

g(b,1).

then

?- bagof(X,g(a,X),Bag). false.

but

?- findall(X,g(a,X),Bag). Bag = [].

## Limited by number of solutions of the Goal only

Note that findall/3 **is** limited by the success of the `Goal`

predicate.

Here it creates a new list holding all 6 values it found:

?- findall(X,between(0,5,X),L). L = [0, 1, 2, 3, 4, 5].

findall/3, similar to bagof/3 and setof/3 **is not** limited by the length of the Bag (and IMHO, this is a design error!) In fact, it probably collects a solution list first, then unifies it with `Bag`

.

Here we give it a Bag of 10 fresh variables to fill with a Goal predicate that redoes forever. findall/3 does not care and goes on ... forever!

?- length(L,10), findall(X,between(0,inf,X),L). ERROR: Stack limit (1.0Gb) exceeded

## Bag length must match number of solutions

If the third argument is not a fresh variable but a list (of fresh variables or otherwise), length must match the number of solutions obtained (this makes sense, "logically"):

?- length(L,5),findall(X,between(0,4,X),L). L = [0, 1, 2, 3, 4]. ?- length(L,5),findall(X,between(0,3,X),L). false. ?- length(L,5),findall(X,between(0,5,X),L). false.

The above also applies to bagof/3 and setof/3

## Edge case

Edge case: findall/3 accepts a non-list Bags instead of throwing a type error. Might be useful to fix that. In the first case below, the unification fails trivially, in the second, it loops forever:

?- length(L,5),findall(X,between(0,4,X),1). false. ?- findall(t,(repeat,fail),1).

## No caret syntax to "shield off" variables

findall/3 does not have a special syntax to indicate which variables in its goal should be "shielded off" from anything outside the inner goal.

With the database

f(a,1). f(b,1). f(c,2). f(d,2).

First instantiation of `f(X,Y)`

fixes `Y`

to 1. Then bagof/3 runs to completion. The the whole toplevel goal succeeds and backtracks. The the second instantiation of `f(X,Y)`

fixes `Y`

to 2:

?- bagof(X,f(X,Y),Bag). Y = 1, Bag = [a, b] ; Y = 2, Bag = [c, d].

Tell bagof/3 to internally backtrack over Y, "existentially qualifying Y" or shielding it off from outside of the bagof/3 call:

?- bagof(X,Y^f(X,Y),Bag). Bag = [a, b, c, d].

which is the same as

bagit(X) :- f(X,_). ?- bagof(X,bagit(X),Bag). Bag = [a, b, c, d].

With findall/3, one gets only the "existentially qualifying" behaviour:

?- findall(X,f(X,Y),Bag). Bag = [a, b, c, d].

If Y is instantiated from outside the call, they behave the same:

?- Y=2,findall(X,f(X,Y),Bag). Y = 2, Bag = [c, d]. ?- Y=2,bagof(X,Y^f(X,Y),Bag). Y = 2, Bag = [c, d]. ?- Y=2,bagof(X,f(X,Y),Bag). Y = 2, Bag = [c, d].

The feel when one gets the impression some proper syntax is missing to make behaviour more explicit.