两个变量列表相等
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
.
的单次执行中保持一致的问题
如何定义一个元逻辑谓词来测试(因此仅成功或失败)如果两个唯一变量列表包含完全相同的变量使用 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
.