这是一种简单的方法,您可以做到这一点并保持逻辑纯度!
not_all_equal([E|Es]) :-
some_dif(Es, E).
some_dif([X|Xs], E) :-
( dif(X, E)
; X = E, some_dif(Xs, E)
).
下面是一些使用 SWI-Prolog 7.7.2 的示例查询。
一、最一般的查询:
?- not_all_equal(Es).
dif(_A,_B), Es = [_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_A,_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_A,_A,_A,_B|_C]
...
接下来,OP在问题中给出的查询:
?- not_all_equal([A,B,C]), A=a, B=b.
A = a, B = b
; false. % <- the toplevel hints at non-determinism
最后,让我们把子目标放在A=a, B=b
前面:
?- A=a, B=b, not_all_equal([A,B,C]).
A = a, B = b
; false. % <- (non-deterministic, like above)
很好,但理想情况下,最后一个查询应该确定性地成功!
第一个参数索引
将第一个谓词参数的主要函子(加上一些简单的内置测试)考虑在内,以提高充分实例化目标的确定性。
这本身并不能dif/2
令人满意地涵盖。
我们能做什么?使用
具体化的术语相等/不等式——有效地索引dif/2
!
some_dif([X|Xs], E) :- % some_dif([X|Xs], E) :-
if_(dif(X,E), true, % ( dif(X,E), true
(X = E, some_dif(Xs,E)) % ; X = E, some_dif(Xs,E)
). % ).
注意新旧实现的相似之处!
上面,目标X = E
在左侧是多余的。让我们删除它!
some_dif([X|Xs], E) :-
if_(dif(X,E), true, some_dif(Xs,E)).
甜的!但是,唉,我们还没有完成(还)!
?- not_all_equal(Xs)。
不终止
这是怎么回事?
事实证明, 的实现使dif/3
我们无法为最一般的查询获得好的答案序列。为此——在不使用强制公平枚举的额外目标的情况下——我们需要一个调整后的实现dif/3
,我称之为diffirst/3
:
diffirst(X, Y, T) :-
( X == Y -> T = false
; X \= Y -> T = true
; T = true, dif(X, Y)
; T = false, X = Y
).
让我们在 predicate 的定义中使用diffirst/3
而不是:dif/3
some_dif/2
some_dif([X|Xs], E) :-
if_(diffirst(X,E), true, some_dif(Xs,E)).
所以,最后,这里有上面的新查询some_dif/2
:
?- not_all_equal(Es). % query #1
dif(_A,_B), Es = [_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_A,_B|_C]
...
?- not_all_equal([A,B,C]), A=a, B=b. % query #2
A = a, B = b
; false.
?- A=a, B=b, not_all_equal([A,B,C]). % query #3
A = a, B = b.
查询 #1 不会终止,但具有相同的简洁紧凑的答案序列。好的!
查询 #2 仍然是不确定的。好的。对我来说,这是最好的。
查询 #3 已成为确定性:现在更好!
底线:
- 用于
library(reif)
驯服过多的不确定性,同时保持逻辑纯度!
diffirst/3
应该找到它的方式library(reif)
:)
编辑:更一般地使用元谓词(由评论建议;谢谢!)
some_dif/2
让我们这样概括:
:- meta_predicate some(2,?).
some(P_2, [X|Xs]) :-
if_(call(P_2,X), true, some(P_2,Xs)).
some/2
可以与除 . 以外的具体谓词一起使用diffirst/3
。
这里的更新not_all_equal/1
现在使用some/2
而不是some_dif/2
:
not_all_equal([X|Xs]) :-
some(diffirst(X), Xs).
上面的示例查询仍然给出相同的答案,所以我不会在这里展示这些。