【问题标题】:How to read the predicates in prolog如何阅读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].

但我不知道如何阅读语法,如果有人可以为我分解它,那就太好了。

【问题讨论】:

    标签: prolog logic


    【解决方案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:你修好了吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多