对我的代码进行哪些最小的更改可以使其保持逻辑纯洁性?
What minimal change to my code would make it preserve logical purity?
我在下面发布了代码 and 它在逻辑上并不纯粹,并且“如果您对代码进行最小的更改以使其保持逻辑纯度感兴趣,我建议发布一个关于这个的新问题。我很乐意回答它:)".
% minset_one(1 in D1, 1 in D2, D1, D2, D1Len, D2Len, T).
minset_one_(true, false, D1, _, _, _, D1).
minset_one_(false, true, _, D2, _, _, D2).
minset_one_(true, true, _, D2, D1Len, D2Len, D2) :- D1Len >= D2Len.
minset_one_(true, true, D1, _, D1Len, D2Len, D1) :- D1Len < D2Len.
minset_one(D1, D2, T) :-
(member(1, D1) -> D1check = true ; D1check = false),
(member(1, D2) -> D2check = true ; D2check = false),
length(D1, D1Len),
length(D2, D2Len),
minset_one_(D1check, D2check, D1, D2, D1Len, D2Len, T).
例如
?- D1 = [X,Y,Z], D2 = [U,V], minset_one(D1,D2,T).
D1 = [1, Y, Z],
D2 = T, T = [1, V],
U = X, X = 1 ;
false
还有更多可能的解决方案。 member(1, D1)
不是通过 [1, Y, Z]
回溯,然后是 [X, 1, Z]
然后是 [X, Y, 1]
.
我认为是:
添加:
:- use_module(library(reif)).
... 并替换:
%(member(1, D1) -> D1check = true ; D1check = false),
%(member(1, D2) -> D2check = true ; D2check = false),
memberd_t(1, D1, D1check),
memberd_t(1, D2, D2check),
成员与memberd_t的区别举例:
?- member(X, [A, B, C]).
X = A ;
X = B ;
X = C.
?- memberd_t(X, [A, B, C], IsMember).
X = A,
IsMember = true ;
X = B,
IsMember = true,
dif(A,B) ;
X = C,
IsMember = true,
dif(A,C),
dif(B,C) ;
IsMember = false,
dif(A,X),
dif(B,X),
dif(C,X).
?- memberd_t(X, [A, B, C], IsMember), X = 5, A = 5, C = 5.
X = A, A = C, C = 5,
IsMember = true ;
false.
因此,memberd_t 本身就是在添加 dif/2 约束。为了稍微提高性能,它只循环一次列表。
memberd_t 的定义在例如https://github.com/meditans/reif/blob/master/prolog/reif.pl#L194 and https://www.swi-prolog.org/pack/file_details/reif/prolog/reif.pl?show=src
(->)/2
(和朋友)的问题
考虑以下目标:
(member(1,D1) -> D1check = true ; D1check = false)
(->)/2
提交 member(1,D1)
的第一个答案——其他答案将被忽略。
(->)/2
的替代品——例如 (*->)/2
(SWI、GNU)或 if/3
(SICStus)——可以帮助我们吗?
No。这些 do 不会忽略使 member(1,D1)
成功的替代答案,但他们不认为 member(1,D1)
的逻辑否定可以 also 已成功。
回归基础:“If P then Q else R” ≡ “(P ∧ Q) ∨ (¬P ∧ R)”
所以让我们将 (If -> Then ; Else)
重写为 (If, Then ; Not_If, Else)
:
(member(1,D1), D1check = true ; non_member(1,D1), D1check = false)
我们应该如何实现non_member(X,Xs)
——我们可以简单地写成\+ member(X,Xs)
吗?
不!为了保持逻辑的纯洁性,我们最好不要建立在“否定是有限的失败”的基础上。
幸运的是,结合 maplist/2
和 dif/2
可以完成这里的工作:
non_member(X,Xs) :-
maplist(dif(X),Xs).
综合起来
所以这是我建议的最小更改:
minset_one_(true, false, D1, _, _, _, D1).
minset_one_(false, true, _, D2, _, _, D2).
minset_one_(true, true, _, D2, D1Len, D2Len, D2) :- D1Len >= D2Len.
minset_one_(true, true, D1, _, D1Len, D2Len, D1) :- D1Len < D2Len.
non_member(X,Xs) :-
maplist(dif(X),Xs).
minset_one(D1, D2, T) :-
(member(1,D1), D1check = true ; non_member(1,D1), D1check = false),
(member(1,D2), D2check = true ; non_member(1,D2), D2check = false),
length(D1, D1Len),
length(D2, D2Len),
minset_one_(D1check, D2check, D1, D2, D1Len, D2Len, T).
运行 我们现在得到的示例查询:
?- D1 = [X,Y,Z], D2 = [U,V], minset_one(D1,D2,T).
D1 = [1,Y,Z], X = U, U = 1, D2 = T, T = [1,V]
; D1 = [1,Y,Z], X = V, V = 1, D2 = T, T = [U,1]
; D1 = T, T = [1,Y,Z], X = 1, D2 = [U,V], dif(U,1), dif(V,1)
; D1 = [X,1,Z], Y = U, U = 1, D2 = T, T = [1,V]
; D1 = [X,1,Z], Y = V, V = 1, D2 = T, T = [U,1]
; D1 = T, T = [X,1,Z], Y = 1, D2 = [U,V], dif(U,1), dif(V,1)
; D1 = [X,Y,1], Z = U, U = 1, D2 = T, T = [1,V]
; D1 = [X,Y,1], Z = V, V = 1, D2 = T, T = [U,1]
; D1 = T, T = [X,Y,1], Z = 1, D2 = [U,V], dif(U,1), dif(V,1)
; D1 = [X,Y,Z], D2 = T, T = [1,V], U = 1, dif(X,1), dif(Y,1), dif(Z,1)
; D1 = [X,Y,Z], D2 = T, T = [U,1], V = 1, dif(X,1), dif(Y,1), dif(Z,1)
; false.
更好。在我看来确实没有遗漏任何东西。
我在下面发布了代码
% minset_one(1 in D1, 1 in D2, D1, D2, D1Len, D2Len, T).
minset_one_(true, false, D1, _, _, _, D1).
minset_one_(false, true, _, D2, _, _, D2).
minset_one_(true, true, _, D2, D1Len, D2Len, D2) :- D1Len >= D2Len.
minset_one_(true, true, D1, _, D1Len, D2Len, D1) :- D1Len < D2Len.
minset_one(D1, D2, T) :-
(member(1, D1) -> D1check = true ; D1check = false),
(member(1, D2) -> D2check = true ; D2check = false),
length(D1, D1Len),
length(D2, D2Len),
minset_one_(D1check, D2check, D1, D2, D1Len, D2Len, T).
例如
?- D1 = [X,Y,Z], D2 = [U,V], minset_one(D1,D2,T).
D1 = [1, Y, Z],
D2 = T, T = [1, V],
U = X, X = 1 ;
false
还有更多可能的解决方案。 member(1, D1)
不是通过 [1, Y, Z]
回溯,然后是 [X, 1, Z]
然后是 [X, Y, 1]
.
我认为是:
添加:
:- use_module(library(reif)).
... 并替换:
%(member(1, D1) -> D1check = true ; D1check = false),
%(member(1, D2) -> D2check = true ; D2check = false),
memberd_t(1, D1, D1check),
memberd_t(1, D2, D2check),
成员与memberd_t的区别举例:
?- member(X, [A, B, C]).
X = A ;
X = B ;
X = C.
?- memberd_t(X, [A, B, C], IsMember).
X = A,
IsMember = true ;
X = B,
IsMember = true,
dif(A,B) ;
X = C,
IsMember = true,
dif(A,C),
dif(B,C) ;
IsMember = false,
dif(A,X),
dif(B,X),
dif(C,X).
?- memberd_t(X, [A, B, C], IsMember), X = 5, A = 5, C = 5.
X = A, A = C, C = 5,
IsMember = true ;
false.
因此,memberd_t 本身就是在添加 dif/2 约束。为了稍微提高性能,它只循环一次列表。
memberd_t 的定义在例如https://github.com/meditans/reif/blob/master/prolog/reif.pl#L194 and https://www.swi-prolog.org/pack/file_details/reif/prolog/reif.pl?show=src
(->)/2
(和朋友)的问题
考虑以下目标:
(member(1,D1) -> D1check = true ; D1check = false)
(->)/2
提交 member(1,D1)
的第一个答案——其他答案将被忽略。
(->)/2
的替代品——例如 (*->)/2
(SWI、GNU)或 if/3
(SICStus)——可以帮助我们吗?
No。这些 do 不会忽略使 member(1,D1)
成功的替代答案,但他们不认为 member(1,D1)
的逻辑否定可以 also 已成功。
回归基础:“If P then Q else R” ≡ “(P ∧ Q) ∨ (¬P ∧ R)”
所以让我们将 (If -> Then ; Else)
重写为 (If, Then ; Not_If, Else)
:
(member(1,D1), D1check = true ; non_member(1,D1), D1check = false)
我们应该如何实现non_member(X,Xs)
——我们可以简单地写成\+ member(X,Xs)
吗?
不!为了保持逻辑的纯洁性,我们最好不要建立在“否定是有限的失败”的基础上。
幸运的是,结合 maplist/2
和 dif/2
可以完成这里的工作:
non_member(X,Xs) :- maplist(dif(X),Xs).
综合起来
所以这是我建议的最小更改:
minset_one_(true, false, D1, _, _, _, D1). minset_one_(false, true, _, D2, _, _, D2). minset_one_(true, true, _, D2, D1Len, D2Len, D2) :- D1Len >= D2Len. minset_one_(true, true, D1, _, D1Len, D2Len, D1) :- D1Len < D2Len. non_member(X,Xs) :- maplist(dif(X),Xs). minset_one(D1, D2, T) :- (member(1,D1), D1check = true ; non_member(1,D1), D1check = false), (member(1,D2), D2check = true ; non_member(1,D2), D2check = false), length(D1, D1Len), length(D2, D2Len), minset_one_(D1check, D2check, D1, D2, D1Len, D2Len, T).
运行 我们现在得到的示例查询:
?- D1 = [X,Y,Z], D2 = [U,V], minset_one(D1,D2,T). D1 = [1,Y,Z], X = U, U = 1, D2 = T, T = [1,V] ; D1 = [1,Y,Z], X = V, V = 1, D2 = T, T = [U,1] ; D1 = T, T = [1,Y,Z], X = 1, D2 = [U,V], dif(U,1), dif(V,1) ; D1 = [X,1,Z], Y = U, U = 1, D2 = T, T = [1,V] ; D1 = [X,1,Z], Y = V, V = 1, D2 = T, T = [U,1] ; D1 = T, T = [X,1,Z], Y = 1, D2 = [U,V], dif(U,1), dif(V,1) ; D1 = [X,Y,1], Z = U, U = 1, D2 = T, T = [1,V] ; D1 = [X,Y,1], Z = V, V = 1, D2 = T, T = [U,1] ; D1 = T, T = [X,Y,1], Z = 1, D2 = [U,V], dif(U,1), dif(V,1) ; D1 = [X,Y,Z], D2 = T, T = [1,V], U = 1, dif(X,1), dif(Y,1), dif(Z,1) ; D1 = [X,Y,Z], D2 = T, T = [U,1], V = 1, dif(X,1), dif(Y,1), dif(Z,1) ; false.
更好。在我看来确实没有遗漏任何东西。