我和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).
我想知道我所犯的错误,也许是对这些术语如何起作用的解释 . 谢谢 .
2 回答
Examination of del/3
(1)此规则表示列表
[P]
是列表[P]
,其中删除了元素S
. 此规则的问题是S
和P
可能是相同的值,因此规则是't always true. If you wanted this to be true all the time (be a valid rule), you' d需要规定S
和P
不能实例化为相同的值:这假设我们甚至需要这个规则,但我们暂时将它留在这里,因为在这个新状态下,它是正确的 .
(2)此规则表示
[]
是列表[S]
,其中元素S
已删除 . 那是真实的 .(3)此规则表示
L2
是[H1,H2|T]
列表,如果H1
和S
统一,L2
删除L2
,则删除了S
. 但是,有一个缺失的论点 . 你有del([H2|T], L2)
但是del/3
被定义为接受3个参数 . 我们假设你的意思是S
是第一个参数(S
仍然是被删除的东西),所以del(S, [H2|T], L2)
. 新修复的规则似乎是合乎逻辑的 .(4)此规则说*
[H1,T2]
是列表[H1,H2|T]
,如果H1
与S
不一致,则删除元素S
,T2
是删除元素S
的列表[H2|T]
. 这与#3有相同的问题,缺少del/3
的参数,我们再次假设它是S
,使它成为del(S, [H2|T], T2)
. 另一个问题是你有[H1,T2]
,它只是两个元素的列表:H1
和T2
. 另一个错字 . 这应该是[H1|T2]
. 所以修复后的规则现在似乎有意义了 .修复这些粗心的错误会导致你的谓词几乎正常工作!当第一个参数被实例化时,它将产生正确的结果:
此外,它可以清理一下 .
H2
并未真正用于第3和第4个子句中 . 在第3个子句中,您可以在谓词的头部实例化S
和H1
. 那么这两个成了:列表上的谓词无效 . 我不确定这是否是故意的,但你可以说
del(X, [], [])
应该是真的(当你从空列表中删除一个元素时会产生一个空列表) . 如果我们包含此规则:我们现在可以摆脱规则(1)和(2),因为(3)和(4)将处理它们并递归到规则(1a) .
此外,在这种情况下,规则仍然失败:
如果这样做会很好,
X = b
. 问题出现在第(4)条中,我们检查H \= S
,这意味着H
和S
不是统一的 . 如果S
是变量,则此表达式对我们起作用,因为H \= S
将始终失败(因为S
确实可以统一为H
) . 所以我们用dif(H,S)
替换它来检查这些术语是否相同 . 有些Prologs不提供dif/2
,在这种情况下,您可以用\==
代替此解决方案(H \== S
) . 我们得到的规则集是:让我们“重读”这些规则:
从空列表中删除的任何元素都是空列表 .
删除了元素
S
的列表[S|T]
是列表L2
如果L2
是列表T
,其中元素S
已删除 .列表
[H|T2]
是列表[H|T]
,如果S
与H
不同,则删除元素S
,T2
是删除元素S
的列表T
.这看起来简单得多,虽然只是几个简单的reworks远离原始 . 它现在会产生这个结果,这很好:
Examination of change/2
(1)这条规则说如果我们改变空列表中的所有2,我们得到空列表 . 听起来不错 .
(2)这条规则说如果我把列表
[H1,H2|T]
并且我更改了2 's to 4' s,如果H1
是2,我会得到L
并将L
追加到[2]
(由于[2]
不可变,因此总是会失败 - 请参阅append/2
和append/3
的在线文档!append/2
是附加列表,例如)和L
是[H2|T]
,其中包含2个's changed to 4' . 这已经不会改变2 's to 4'为什么我要为[2]
追加一些东西?我们需要丢失append
并简单地将L
统一为[4|T2]
,其中T2
是[H2|T]
及其2 's changed to 4' . 或者换句话说:这可以使用如上所述的在条款的头部中结合统一的方法进一步简化 . 另请注意,我们也没有真正使用
H2
在这里可见 . 所以[H2|T]
可以只是T
:因此,如果有2,则使用4代替2,然后处理尾部 .
(3)此规则与
append/2
查询具有相同的问题(2) . 我们可以遵循与规则(2)相同的模式,并修复不相等的检查:因此,如果它不是2,我们只是继承元素
H
,然后处理尾部 . 完整的change
谓词如下所示:重读规则,看到它们具有逻辑意义:
在空列表中更改2 's to 4'是空列表 .
在列表
[2|T]
中更改2 's to 4'是列表[4|T2]
,如果T2
是列表T
,其中包含2 's changed to 4' .在列表
[H|T]
中更改2 's to 4'是列表[H|T2]
如果H
不是2
而T2
是列表T
,其中包含2 's changed to 4' .让我们从最简单的两个开始:
change/2
. 两个列表具有相同的长度,并且它们基本相同 - 对于2的出现是安全的,应该由4替换 . 因此,首先为这样的对定义关系:您可以出于性能原因对此进行优化
现在,您的实际定义是
或者更详细地说:
要将此定义与建议的其他定义进行比较,请考虑以下查询:
Further uses