我与Prolog完全混淆。我有两个简单的谓词,我试图弄清楚,但似乎无法使它们正确。首先,我试图找出一个删除谓词的变体,我需要从List1中删除给定元素的所有出现,并查看它是否等于List2。
这就是我的尝试。
del(S,[P],[P]).
del(S,[S],[]).
del(S,[H1,H2|T],L2) :- H1 = S, del([H2|T],L2).
del(S,[H1,H2|T],[H1,T2]) :- H1 \= S, del([H2|T],T2).
另一个谓词采用两个列表,并在List1中取出所有出现的元素2,并将其替换为4,并查看List1是否与List2相同。为了简化,没有子列表。
这些是我尝试过的。
change([],[]).
change([H1,H2|T],L) :- H1 = 2, append([2],L), change([H2|T],L).
change([H1,H2|T],L) :- H1 \= 2, append(H1,L), change([H2|T],L).
我想知道我所犯的错误,也许是对这些术语如何起作用的解释。谢谢。
答案 0 :(得分:3)
考试del/3
(1) del(S,[P],[P]).
(2) del(S,[S],[]).
(3) del(S,[H1,H2|T],L2) :- H1 = S, del([H2|T],L2).
(4) del(S,[H1,H2|T],[H1,T2]) :- H1 \= S, del([H2|T],T2).
(1)此规则表明列表[P]
是已删除元素[P]
的列表S
。此规则的问题是S
和P
可能是相同的值,因此规则始终不正确。如果您希望这一直是真实的(成为有效规则),则您需要规定S
和P
无法实例化为相同的值:< / p>
del(S, [P], [P]) :- S \= P.
假设我们甚至需要这条规则,但我们暂时将它留在这里,因为在这个新状态下,它是正确的。
(2)此规则表明 []
是已删除元素[S]
的列表S
。那是真的。
(3)此规则表明,如果L2
和[H1,H2|T]
统一且{S
, H1
就会移除S
列表L2
1}} [H2|T]
移除S
。但是,缺少参数。您有del([H2|T], L2)
但del/3
被定义为接受3个参数。我们假设您的意思是S
是第一个参数(S
仍然被删除了),所以del(S, [H2|T], L2)
。新修复的规则似乎是合乎逻辑的。
(4)此规则表明* [H1,T2]
是[H1,H2|T]
列表,如果S
与H1
无法统一,则S
已移除T2
{1}}列表[H2|T]
已移除元素S
。这与#3有相同的问题,缺少del/3
的参数,我们再次假定它是S
,使其成为del(S, [H2|T], T2)
。另一个问题是,您有[H1,T2]
这是仅包含两个元素的列表:H1
和T2
。另一个错字。这应该是[H1|T2]
。因此修复后的规则现在似乎有意义了。
修复这些粗心错误导致你的谓词几乎可以正常工作!当第一个参数被实例化时,它将产生正确的结果:
| ?- del(a, [a,b,c,a,d,a], L).
L = [b,c,d] ? a
no
此外,它可以清理一下。 H2
并未真正用于第3和第4条款。在第3个子句中,您可以在谓词的头部实例化S
和H1
。所以那两个成了:
(3) del(S, [S|T], L2) :- del(S, T, L2).
(4) del(S, [H|T], [H|T2]) :- H \= S, del(S, T, T2).
列表中的谓词无效。我不确定这是否是故意的,但你可以说del(X, [], [])
应该是真的(当你从空列表中删除一个元素时会产生一个空列表)。如果我们包含此规则:
(1a) del(_, [], []).
我们现在可以摆脱规则(1)和(2),因为(3)和(4)将处理它们并递归到规则(1a)。
此外,在这种情况下规则仍然失败:
| ?- del(X, [a,b,c], [a,c]).
no
如果这样做会很好,X = b
。问题出在第(4)条中,我们检查H \= S
,这意味着 H
和S
不是统一的。如果S
是变量,则此表达式对我们起作用,因为H \= S
将始终失败(因为S
确实可以统一为H
)。因此我们将其替换为dif(H,S)
以检查这些术语是否相同。
有些Prolog不提供dif/2
,在这种情况下,您可以用\==
替换此解决方案(H \== S
)。我们得到的规则集是:
(1) del(_, [], []).
(2) del(S, [S|T], L2) :- del(S, T, L2).
(3) del(S, [H|T], [H|T2]) :- dif(H, S), del(S, T, T2).
让我们重读&#34;这些规则:
[S|T]
的列表S
是列表L2
,如果 L2
是列表T
,则元素S
已删除。[H|T2]
与[H|T]
不同,S
列表S
已移除的元素H
,{ {1}}列表T2
已删除元素T
。这看起来简单得多,虽然只是简单的几次改造远离原版。它现在将产生这个结果,这很好:
S
考试| ?- del1(X, [a,b,c,b,d], [a,c,d]).
X = b ? ;
(1 ms) no
change/2
(1)这条规则说如果我们改变空列表中的所有2,我们得到空列表。听起来不错。
(2)此规则说明如果我将列表(1) change([],[]).
(2) change([H1,H2|T],L) :- H1 = 2, append([2],L), change([H2|T],L).
(3) change([H1,H2|T],L) :- H1 \= 2, append(H1,L), change([H2|T],L).
和2更改为4,如果[H1,H2|T]
为2,我会L
我将H1
追加到L
(由于[2]
不变,因此会始终失败 - 请参阅[2]
和append/2
的在线文档!{{1}例如,}用于附加列表列表,而append/3
是append/2
,其中2更改为4&s。这根本没有任何逻辑意义。如果我将2改为4,为什么我要向L
添加内容?我们需要丢失[H2|T]
,只需将[2]
与append
统一L
[4|T2]
,其中{2}已更改为4&s 。换句话说:
T2
这可以使用如上所述在条款的头部中结合统一的方法进一步简化。另请注意,我们并没有真正使用[H2|T]
在这里可见。因此(2) change([H1,H2|T], L) :- H1 = 2, L = [4|T2], change([H2|T], T2).
只能是H2
:
[H2|T]
所以我们使用4而不是2,如果有2,则处理尾部。
(3)此规则与T
查询具有相同的问题(2)。我们可以遵循与规则(2)相同的模式,并修复不相等的检查:
(2) change([2|T], [4|T2]) :- change(T, T2).
所以我们只是继承元素append/2
,如果它不是2,那么处理尾巴。完整的(3) change([H|T], [H|T2]) :- H \== 2, change(T, T2).
谓词如下所示:
H
重新阅读规则,看到它们具有逻辑意义:
change
是列表{{1>,则列表(1) change([], []).
(2) change([2|T], [4|T2]) :- change(T, T2).
(3) change([H|T], [H|T2]) :- H \== 2, change(T, T2).
中的2到2更改为列表[2|T]
将2&2更改为4&#39; s。[4|T2]
不是T2
,则列表T
中的2到2更改为列表[H|T]
}和[H|T2]
是列表H
,其中2更改为4。答案 1 :(得分:1)
让我们从最简单的两个开始:change/2
。两个列表都具有相同的长度,它们基本相同 - 对于2的出现是安全的,应该用4代替。所以让我们首先定义这样一对的关系:
exch(2, 4).
exch(X, X) :-
dif(X, 2).
您可以出于性能原因
进行优化exch(A, B) :-
( A == 2 -> B = 4
; A \= 2 -> A = B
; A = 2, B = 4
; A = B, dif(A,2)
).
现在,您的实际定义是
change(Xs, Ys) :-
maplist(exch, Xs, Ys).
或更详细地说:
change([], []).
change([A|As], [B|Bs]) :-
exch(A, B),
change(As, Bs).
要将此定义与建议的其他定义进行比较,请考虑以下查询:
?- change([X],[Y]).
X = 2,
Y = 4 ;
X = Y,
dif(Y, 2).
del(E, Xs, Ys) :-
tfilter(dif_truth, Xs, Ys).
dif_truth(X, Y, true) :-
dif(X, Y).
dif_truth(X, X, false).
tfilter( _, [], []).
tfilter(CT, [E|Es], Fs0) :-
call(CT,E,Truth),
( Truth = false,
Fs0 = Fs
; Truth = true,
Fs0 = [E|Fs]
),
tfilter(CT, Es, Fs).