由于您有一些逻辑背景,您可能会发现将规则作为逻辑公式来阅读会很有帮助。让我们将 (\==)/2 替换为 dif/2 然后 remove/3 如下所示:
remove([], _, []) ← true
remove([X | Xs], X, Ys) ← remove(Xs, X, Ys)
remove([Y | Xs], X, [Y | Ys]) ← dif(X,Y) ∧ remove(Xs, X, Ys)
注意暗示箭头如何指向规则的头部。这意味着规则的主体是前件,规则的头部是结果。因此,您将规则解读为:如果规则的主体为真,则规则的主体为真。规则中的目标通过连词连接起来。请注意事实如何将true 作为先行词,这意味着remove([], _, []) 始终为真。另一方面,如果规则的主体为假,则该规则失败,但如果另一个规则的主体为真,则谓词仍可能成功。如果所有其他规则的主体也为假,则谓词失败。因此,为谓词设置多个规则构成逻辑或:如果 rule1 OR rule2 OR rule3 成功,则谓词 remove/3 成功。
正如您特别要求语法一样,熟悉列表的头部和尾部表示法也是合适的。也就是说,您可以显式编写列表的第一个元素,然后是列表构造函数| 和列表的其余部分:
[1|Xs] ...列表以1开头,然后有一个休息
[1,2|Xs] ...列表以1 和2 开头,后跟一个休息
[X|Xs] ...列表至少有一个元素后跟一个休息
注意列表元素是如何用, 分隔的,而列表的其余部分是如何用| 分隔的。 | 后面的词实际上是一个列表,也可以是一个空列表。以下是相等列表的一些示例:
[1] 与[1|[]] 相同
[1,2] = [1|[2]] = [1|[2|[]]] = [1,2|[]]
对于下面的列表,已经有 8 种写法:
[1,2,3] = [1,2|[3]] = [1|[2,3]] = [1|[2|[3|[]]]] = ...
考虑到上述观察结果,您将一次检查一项规则。正如@lurker 在他的回答中已经这样做了,我不会详细说明。但是,我要补充一点,如果一条规则有多个目标,例如您示例中的第三条规则,我发现一次完成一个目标很有帮助:
remove([Y | Xs], X, [Y | Ys]) :-
原始列表的元素Y也在列表中,没有X IF...
remove([Y | Xs], X, [Y | Ys]) :-
dif(X,Y),
...X 不同于 Y 并且...
remove([Y | Xs], X, [Y | Ys]) :-
dif(X,Y),
remove(Xs, X, Ys).
...Xs、X 和 Ys 的关系也成立。
那么为什么要更换呢?内置谓词 (\==)/2 只是成功或失败,没有统一或副作用。它有利于在给定时间测试术语不等式,但以后不会产生任何影响。考虑以下查询:
?- X=Y, X\==Y.
no
首先变量X 和Y 统一,随后不等式测试失败。但是:
?- X\==Y, X=Y.
X = Y
首先,不等式测试成功,否则 Prolog 甚至不会考虑第二个目标。那么X和Y就统一成功了。这就是我所说的以后没有影响的意思。所以我上面写的关于阅读谓词的所有内容对于 (\==)/2 并没有真正的意义。
作为一个较短的版本,我使用if_/3 和=/3:
list_without_element([],[],_E).
list_without_element([X|Xs],L,E) :-
if_(X=E,L=Ys,L=[X|Ys]),
list_without_element(Xs,Ys,E).