如何阅读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] ...列表以12 开头,后跟一个休息

[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).

...XsXYs 的关系也成立。

那么为什么要更换呢?内置谓词 (\==)/2 只是成功或失败,没有统一或副作用。它有利于在给定时间测试术语不等式,但以后不会产生任何影响。考虑以下查询:

   ?- X=Y, X\==Y.
no

首先变量XY 统一,随后不等式测试失败。但是:

   ?- X\==Y, X=Y.
X = Y

首先,不等式测试成功,否则 Prolog 甚至不会考虑第二个目标。那么XY就统一成功了。这就是我所说的以后没有影响的意思。所以我上面写的关于阅读谓词的所有内容对于 (\==)/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/3dif/3list_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 元素 if XY 不同,Ys 是我删除所有元素后得到的列表X 来自Xs 的元素。

作为练习,您应该尝试再次阅读这些内容,但使用更相关的名称,例如我提供的重命名示例。

【讨论】:

完美,谢谢,语法真的让我很困惑,似乎与我通常阅读谓词的方式大不相同。 @user6248190 我首先想到了一个谓词子句,Such-and-such is true if .... 后面跟着一个条件序列。 对不起还有一件事,有没有更短的方法来做删除谓词正在做的事情?为什么有3行remove? @false 谢谢你。仍在学习dif/2 的精妙之处。 @lurker:你修好了吗?

以上是关于如何阅读prolog中的谓词的主要内容,如果未能解决你的问题,请参考以下文章

如何通过Prolog将字符串连接到列表中的多个元素?

Prolog 中的谓词控制

如何将用户输入转换为 gnu prolog 中的可重用谓词?

Prolog 中如何表示谓词逻辑?

Prolog 中的“行为良好的谓词”是啥?

Prolog 中的子列表谓词