我试图在prolog中比较两个列表,如
?- compare([[X],Y,Z],[[A],B,C]).
true.
?- compare([X,Y,Z],[[A],B,C]).
false.
我不能使用== / 2运算符,因为逻辑变量不一样, 所以这会对两种情况都评估为假。 我显然不能使用= / 2,因为在两种情况下都会评估为真。
有关如何解决此问题的任何建议?
答案 0 :(得分:4)
检查两个术语是否具有相同结构的替代解决方案是使用ISO Prolog标准谓词subsumes_term/2
。当术语是另一个术语的变体时,以下谓词variant/2
为真:
variant(Term1, Term2) :-
\+ \+ subsumes_term(Term1, Term2),
\+ \+ subsumes_term(Term2, Term1).
使用双重否定避免实例化参数中的任何变量。使用例如用于测试的GNU Prolog:
| ?- variant([[X],Y,Z],[[A],B,C]).
(1 ms) yes
| ?- variant([X,Y,Z],[[A],B,C]).
no
答案 1 :(得分:1)
如果您只是想匹配列表结构,可能是这样的:
compare([H1|T1], [H2|T2]) :-
is_list(H1),
is_list(H2),
compare(H1, H2),
compare(T1, T2).
compare([H1|T1], [H2|T2]) :-
\+ is_list(H1),
\+ is_list(H2),
compare(T1, T2).
compare([], []).
| ?- compare([[X],Y,Z],[[A],B,C]).
true ? ;
no
| ?- compare([X,Y,Z],[[A],B,C]).
no
这个解决方案的优点在于,无论变量是否被实例化,它都将起作用。
| ?- compare([[a],b,c], [[d],X,f]).
true ? ;
no
| ?-
答案 2 :(得分:1)
这适用于所提供的测试用例
elemcmp(A,B) :- var(A), var(B), ! ; A =@= B.
?- maplist(elemcmp,[[X],Y,Z],[[A],B,C]).
true.
?- maplist(elemcmp,[X,Y,Z],[[A],B,C]).
false.
答案 3 :(得分:1)
您可以使用(SWI Prolog,至少),=@=
/2。像Term1 =@= Term2
这样的测试是真的
如果
Term1
是(或结构上等同于)Term2
的变体。 对变体的测试弱于等价(==
/ 2), 但比统一更强(=
/ 2)。 两个术语A
和B
是变体iff [ sic ]存在变量的重命名 在A
中,A
等效(==
)到B
,反之亦然。
基本上,foo(A,B)
和foo(B,C)
以及foo(C,D)
是彼此的变体,而不是foo(A,A)
的变体。
针对匿名变量的测试表现如您所料:foo(_,_)
是foo(A,B)
的变体,但不是foo(A,A)
的变体(因为匿名变量的所有用法都是不同的)。
答案 4 :(得分:0)
这是另一种解决方案:
compare(A, B) :- (var(A); var(B)), !, var(A), var(B).
compare([], []).
compare([H1|T1], [H2|T2]) :- compare(H1, H2), compare(T1, T2).
要接受原子,请使用\+ is_list(...)
或等效代替var(...)
。