如何阅读prolog中的谓词
Posted
技术标签:
【中文标题】如何阅读prolog中的谓词【英文标题】:How to read the predicates in prolog 【发布时间】:2016-08-18 00:26:36 【问题描述】:在学习了命题和谓词逻辑后,我转而使用 Prolog。
我想知道是否有人可以为我澄清语法,因为我无法阅读它。
我可以轻松阅读以下内容。原来如此
如果 X 是 Y 的孩子,X 是 Y 的后代。
接着说
如果 X 是 Z 的孩子并且 Z 是 Y 的后代,则 X 是 Y 的后代。
descend(X,Y) :-
child(X,Y).
descend(X,Y) :-
child(X,Z),
descend(Z,Y).
但是,一旦我开始研究列表编程,我就很难阅读谓词的语法。比如下面的
remove([], _, []).
remove([X | Xs], X, Ys) :- remove(Xs, X, Ys).
remove([Y | Xs], X, [Y | Ys]) :- X \== Y, remove(Xs, X, Ys).
通过测试,它会删除第二项,例如,如果我输入
remove([a,b,c], b, Ys).
我会得到Ys = [a,c].
但我不知道如何阅读语法,如果有人可以为我分解它,那就太好了。
【问题讨论】:
【参考方案1】:由于您有一些逻辑背景,您可能会发现将规则作为逻辑公式来阅读会很有帮助。让我们将 (\==)/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).
【讨论】:
或者,更简洁地使用tfilter/3
和dif/3
:list_without_element(Es,Xs,E) :- tfilter(dif(E),Es,Xs).
【参考方案2】:
您需要测试它只是为了看看它做了什么,这表明remove/3
可能没有那么好命名。 remove
非常通用,并留下了“删除什么?”的问题。此外,它是必要的,Prolog 想要关系。也许更好的名字是list_without/3
,它表示第三个参数中的列表是第一个参数中的列表,但没有第二个参数。
尽管如此,让我们看看你有什么。
阅读您的remove/3
谓词可以如下完成:
remove([], _, []).
如果我删除任何元素,空列表仍然是空列表。
remove([X | Xs], X, Ys) :- remove(Xs, X, Ys).
列表
Ys
是列表[X|Xs]
删除了X
元素如果Ys
是我从Xs
中删除所有X
元素后得到的列表。
remove([Y | Xs], X, [Y | Ys]) :- X \== Y, remove(Xs, X, Ys).
[Y|Ys]
是列表[Y|Xs]
删除了X
元素 ifX
与Y
不同,Ys
是我删除所有元素后得到的列表X
来自Xs
的元素。
作为练习,您应该尝试再次阅读这些内容,但使用更相关的名称,例如我提供的重命名示例。
【讨论】:
完美,谢谢,语法真的让我很困惑,似乎与我通常阅读谓词的方式大不相同。 @user6248190 我首先想到了一个谓词子句,Such-and-such is true if .... 后面跟着一个条件序列。 对不起还有一件事,有没有更短的方法来做删除谓词正在做的事情?为什么有3行remove? @false 谢谢你。仍在学习dif/2
的精妙之处。
@lurker:你修好了吗?以上是关于如何阅读prolog中的谓词的主要内容,如果未能解决你的问题,请参考以下文章