我正在尝试编写一个Prolog(CLP)谓词,该谓词将构建约束两个列表不等式的约束。
更正式地说,有两个列表A=[A1,...,AN], B=[B1,...,BN]
约束被定义为(A1 #\= B1) #\/ (A2 #\= B2) #\/ ... #\/ (AN #\= BN)
。
我不确定如何在给定两个任意长度的列表的情况下构建此约束。这是我的尝试。我明白为什么它不起作用,但无法修复它。
any_different([], []).
any_different([H1|T1], [H2|T2]):-
H1 #\= H2 #\/ any_different(T1, T2).
答案 0 :(得分:9)
你需要建立析取并通过第三个参数返回它:
any_different([], [], V) :-
V #= 0. % no differences between [] and []
any_different([H1|T1], [H2|T2], Disj) :-
any_different(T1, T2, Disj0),
Disj #<==> (H1 #\= H2) #\/ Disj0.
现在,调用any_different(List1, List2, AnyDiff)
会限制变量AnyDiff
,您可以将变量与其他变量一起传递给标记谓词。通过陈述AnyDiff #= 0
,您可以约束List1
和List2
相等,而AnyDiff #= 1
会导致它们不相等。
答案 1 :(得分:4)
我认为,至少在SWI-Prolog中,谓词dif / 2和库(clpfd)可以作为具体化的替代方案:
?- L=[X,Y,Z], L ins 1..3, dif(L,[1,2,3]), label(L).
L = [1, 1, 1],
X = Y, Y = Z, Z = 1 ;
L = [1, 1, 2],
X = Y, Y = 1,
Z = 2 ;
...
答案 2 :(得分:4)
以下是基于sum/3
和clpfd具体化(#<==>)/2
的实施:
not_equals_reified(X, Y, B) :-
X #\= Y #<==> B.
any_different(Xs, Ys) :-
maplist(not_equals_reified, Xs, Ys, Bs),
sum(Bs, #>, 0).
使用meta-predicate maplist/4
我们甚至不需要编写递归代码!