Another approach. If we provide ourselves with these higher order predicates (which are each useful on their own),
select_with(_, _, [], []).
select_with(P, X, [Y|Ys], Ys) :- call(P, X, Y), !.
select_with(P, X, [Y|Ys], [Y|Ks]) :-
select_with(P, X, Ys, Ks).
foldl(_,[],Vn,Vn).
foldl(P,[X|Xs],V0,Vn) :-
call(P,X,V0,V1),
foldl_(P,Xs,V1,Vn).
then we can easily define a predicate that is true if each member one list has an equal element in the other (using ==/2
):
members_equal(A, B :-
foldl(select_with(==), A, B, []).
This predicate can be specialized for the stated purpose if we verify that the incoming arguments are varsets. The following is the best I've been able to come up with in that direction (but it eats up quite a few inferences):
is_varset([]).
is_varset([V|Vs]) :-
var(V),
maplist(\==(V), Vs),
is_varset(Vs).
(At least on SWI Prolog, using sort/2
takes fewer inferences than the above. Presumably this is because the sorting is done in C. Also, this answer still doesn't approach the elegance of the term_vars/2
approach——such is the power of "semantic ascent" :)
As
andBs
really are sets of free variables. In my answer that is guaranteed by the fact that they must unify with the second argument ofterm_variables/2
. – Tudor Berariuvarset_seteq([A+B,a],[])
succeeds in many systems (by default). ... and unifies the arguments. – false