两个变量列表相等

Equality of two lists of variables

如何定义一个元逻辑谓词来测试(因此仅成功或失败)如果两个唯一变量列表包含完全相同的变量使用 the built-ins from the current ISO standard (ISO/IEC 13211-1:1995 including Cor.2)。

换句话说,如果一个唯一变量列表是另一个列表的排列,则谓词应该成功。类比于library(ordsets),我们称这个元逻辑谓词为varset_seteq(As, Bs).

请注意,与 ord_seteq/2 相反,此谓词不能简单地是 As == Bs

我建议的解决方案使用 term_variables/2 检查 Bs 是否没有超过 As 的额外变量,并且 As 没有未出现在 Bs.

varset_seteq(As, Bs):-
    term_variables(As-Bs, As),
    term_variables(Bs-As, Bs).

可以使用不是自由变量集的参数来欺骗上述解决方案:

 | ?- varset_seteq([A], [a]).

 A = a

 yes

为避免这种情况,统一可以用等价性测试代替:

varset_seteq(As, Bs):-
    term_variables(As-Bs, A0),
    A0 == As,
    term_variables(Bs-As, B0),
    B0 == Bs.

另一个解决方案,不如效率比 Tudor 的聪明解决方案因此 推荐,但仍然值得一提,因为我看到它被使用在多个场合,是:

varset_seteq(As, Bs) :-
    sort(As, Sa), sort(Bs, Sb), Sa == Sb.

另一种方法。如果我们为自己提供这些高阶谓词(它们各自都有用),

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).

然后我们可以轻松地定义一个谓词,如果一个列表中的每个成员在另一个列表中都有一个相等的元素(使用 ==/2),则该谓词为真:

members_equal(A, B :-
    foldl(select_with(==), A, B, []).

如果我们验证传入的参数是 varsets,这个谓词可以专门用于指定的目的。以下是我在这个方向上所能想到的最好的(但它消耗了很多推论):

is_varset([]).
is_varset([V|Vs]) :-
    var(V),
    maplist(\==(V), Vs),
    is_varset(Vs).

(至少在 SWI Prolog 上,使用 sort/2 比上面的推论更少。大概这是因为排序是在 C 中完成的。此外,这个答案仍然没有接近 term_vars/2方法——这就是"semantic ascent"的力量:)

如果我们可以假设这两个列表包含唯一变量,则以下双重否定的使用有效:

varset_seteq(As, Bs) :-
    \+ \+ (numbered_from(As, 1),
           sort(Bs, SBs),
           As == SBs).

numbered_from([], _).
numbered_from([X|Xs], X) :-
    X1 is X + 1,
    numbered_from(Xs, X1).

这类似于 Paulo 的解决方案,但避免了变量排序仅由 ISO/IEC 13211-1 要求在 sort/2.

的单次执行中保持一致的问题