I sometimes use findall/3
to instantiate all elements of a list to some constant, for example:
?- Xs = [X,Y,Z], findall(a, member(a,Xs), Xs).
Xs = [a, a, a],
X = Y, Y = Z, Z = a.
But I was surprised to find that when the list is partially ground, the same query fails:
?- Xs = [X,b,c], findall(a, member(a,Xs), Xs).
false.
When I look at the result of the first query, I think of the list Xs
as the list [X,Y,Z]
with each of its variables bound to a
. But that is not right! The list in the last argument of findall/3
is not the same list as the list Xs
created before the call to findall/3
. Instead, the two lists are unified, or attempted to be unified, when the call to findall/3
exits. This becomes evident when I rename the âoutputâ list:
?- Xs = [X,b,c], findall(a, member(a,Xs), Ys).
Xs = [X, b, c],
Ys = [a].
The list Ys = [a]
is the list of all instantiations of the term in the first argument of findall/3
. Clearly, [X, b, c]
and [a]
do not unify!
Note that setof/3
and bagof/3
have the same behaviour:
?- Xs = [X,b,c], setof(a, member(a,Xs), Xs).
false.
?- Xs = [X,b,c], bagof(a, member(a,Xs), Xs).
false.
So it seems I had the wrong idea about the semantics of findall/3
et al. It took me a while to realise my mistake and Iâm posting this here just in case someone else has been scratching their head about something similar.
(of course now that Iâve put that down in writing it all sounds trivial and like Iâm just dumb : )