The docs say,
The actual implementation uses findall/3 on a template created from the variables shared between Generator and Goal. Subsequently, it uses every instance of this template to instantiate Goal, call Goal and undo only the instantiation of the template and not other instantiations created by running Goal.
You can see this “variables shared” if you try these queries:
?- length(L, 3), length(K, 3), L = K, foreach(nth1(N,L,N),nth1(N,K,N)).
L = K, K = [_, _, _].
?- length(L, 3), length(K, 3), foreach(nth1(N,L,N),nth1(N,K,N)).
L = [_, _, _],
K = [1, 2, 3].
?- length(L, 3), length(K, 3), foreach(nth1(N,L,N),nth1(N,K,N)), L = K.
L = K, K = [1, 2, 3].