Of course, we are talking about term **as it is at call time**, not **as it syntactically appears in the code** :

For example. the same query as in the example, but `Y`

is no longer an unbound variable. It thus does not appear in the result:

?- Y=foo(Z), term_variables(a(X, b(Y, X), Z), L). Y = foo(Z), L = [X,Z].

Below, `Y`

is bound to `foo(A)`

, becoming bound but introducing another unbound variable:

?- Y=foo(A),term_variables(a(X, b(Y, X), Z), L). Y = foo(A), L = [X,A,Z].

Using the anonymous variable gives exactly what is expected:

?- term_variables(a(_, b(_, _), _), L). L = [_12464,_12458,_12460,_12468].

If a variable becomes bound later, the answer will reflect that:

?- term_variables(a(X, b(Y, X), Z), L),X=1. X = 1, L = [1,Y,Z].

This can be used to collect the bindings for an unknown goal (in case you have to do that, but if your goal is unknown ... how are you going to interprete the bindings?)

?- Goal=member(X-Y,[1-2,3-4,5-6]), term_variables(Goal,Vars), findall(Vars,Goal,Bag). Goal = member(X-Y,[1-2,3-4,5-6]), Vars = [X,Y], Bag = [[1,2],[3,4],[5,6]].

?- Goal=member(X-4,[1-A,3-4,5-B]), term_variables(Goal,Vars), bagof(Vars,Goal,Bag). Goal = member(X-4,[1-A,3-4,5-B]), Vars = [X,A,B], Bag = [[1,4,_6574],[3,_6544,_6550],[5,_6520,4]].