Prolog 两个变量列表的相等性

Prolog 两个变量列表的相等性,prolog,iso-prolog,Prolog,Iso Prolog,如何使用当前ISO标准(ISO/IEC 13211-1:1995,包括ISO/IEC 13211-1:1995)定义一个元逻辑谓词,该谓词在两个唯一变量列表包含完全相同的变量时进行测试(因此仅成功或失败) 换句话说,如果一个唯一变量列表是另一个变量的排列,则谓词应该成功。与之类似,我们将此元逻辑谓词称为varset\u seteq(As,Bs)。 注意,与ord_seteq/2相反,这个谓词不能简单地是As==Bs我建议的解决方案使用术语变量/2来检查Bs是否比As有额外的变量,并且As没有不出

如何使用当前ISO标准(ISO/IEC 13211-1:1995,包括ISO/IEC 13211-1:1995)定义一个元逻辑谓词,该谓词在两个唯一变量列表包含完全相同的变量时进行测试(因此仅成功或失败)

换句话说,如果一个唯一变量列表是另一个变量的排列,则谓词应该成功。与之类似,我们将此元逻辑谓词称为
varset\u seteq(As,Bs)。


注意,与
ord_seteq/2
相反,这个谓词不能简单地是
As==Bs
我建议的解决方案使用
术语变量/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.

另一个解决方案,比都铎的聪明解决方案效率低,因此不推荐,但在这里仍然值得一提,因为我看到它被多次使用,它是:

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

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

然后,我们可以很容易地定义一个谓词,如果一个列表中的每个成员在另一个列表中具有相等的元素(使用
==/2
):

如果我们验证传入的参数是变量集,则可以将该谓词专用于所述目的。以下是我在这方面所能想到的最好的结果(但它吞噬了很多推论):


(至少在SWI Prolog上,使用
sort/2
比上述方法需要更少的推理。这可能是因为排序是用C完成的。而且,这个答案仍然没有接近
术语\u vars/2
方法的优雅程度——这就是“语义提升”的力量:)

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

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

时保持一致的问题。如果谓词的两个参数中的任何一个不是唯一变量列表,则谓词失败?只是等待,可能有更多不同的答案。我尝试了一些不同的方法,但我必须检查
As
Bs
是否真的是自由变量集。在我的回答中,它们必须与
term\u variables/2
的第二个参数统一,这一点得到了保证。不,这不是保证,你也必须假设它
varset_seteq([A+B,A],])
在许多系统中成功(默认情况下)。。。我明白为什么。非常感谢。我在我的回答中加入了这个观察。你的反例真的是最好的!遗憾的是,否则
term_variables/2
可能会利用这样一个事实,即它无论如何都必须检查第二个参数的良好性,因此计算它的长度是免费的,这可能会导致更早的失败。我喜欢这种方法!但是,你不也需要检查一下列表是否只是条形图吗?我现在不在我的电脑旁,但不会成功吗?不,它不会成功。什么是酒吧?哦,是的。我的错。我的大脑短路了。我明白了:因为您根据相应的列表测试每个术语变量列表。我认为这是一个很好的解决方案。条形图是var的拼写错误。对不起:)我最初的答案是:),尽管我还添加了
varlist/1
谓词来检查两个列表是否都由变量组成。但后来我意识到,都铎·贝里乌指出,这种方法将在以下领域取得成功:例如,
As=[A,A,B,C],Bs=[B,C,B,C,A]
。我可能也应该放弃我最初的尝试。虽然此解决方案将在具体的Prolog实现中工作,但它依赖于Prolog实现的依赖于实现的属性。在目标
Sa==Sb
时,不再保证
Sa
Sb
仍然被排序。设想一个GC发生在一个不保留变量顺序的实现中——当它在
sort/2
@aBathologist:-)期间不调用GC时,可能仍然符合要求——详细说明明显的替代解决方案的陷阱总是值得的。然而,最初的问题确实说明了输入是“两个唯一变量列表”(我的重点)。@PauloMoura Oh yeah。你说得对!我的阅读一直徘徊在falsel是否意味着如果列表不是“varset”,谓词本身应该失败,或者如果它可以预期其参数将是varset。现在,通过您的强调,它可以预期变量集(就像
ord_seteq/1
预期但不测试有序集一样)。
members_equal(A, B :-
    foldl(select_with(==), A, B, []).
is_varset([]).
is_varset([V|Vs]) :-
    var(V),
    maplist(\==(V), Vs),
    is_varset(Vs).
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).