读一下!在Prolog

时间:2016-12-02 13:32:02

标签: prolog prolog-cut

我正在阅读Learn Prolog Now! 's chapter on cuts并同时阅读Bratko的人工智能Prolog编程,第5章:控制回溯。起初,似乎切割是模仿其他编程语言中已知的if-else子句的直接方式,例如。

# Find the largest number
max(X,Y,Y):- X =< Y,!. 
max(X,Y,X).

然而,正如下面所说的那样,即使我们期望false,所有变量都被实例化,这段代码也会失败,例如

?- max(2,3,2).
true.

原因很清楚:第一条规则失败,第二条规则不再有任何条件,所以它会成功。我理解这一点,但随后提出了一个解决方案(这里是一个swish):

max(X,Y,Z):- X =< Y,!, Y = Z. 
max(X,Y,X).

我很困惑我应该怎么读这个。我认为!意味着:'如果此!之前的所有内容都为真,则停止终止,包括具有相同谓词的任何其他规则'。但这是不对的,因为这意味着Y = Z的实例化只会在失败的情况下发生,这对于该规则是无用的。

那么如何以“人性化”方式阅读剪辑?并且,作为扩展,我应该如何阅读上面max/3的建议解决方案?

2 个答案:

答案 0 :(得分:3)

另请参阅this answerthis question

  

我应该如何阅读上述max / 3的建议解决方案?

max(X,Y,Z):- X =< Y, !, Y = Z. 
max(X,Y,X).

您可以按如下方式阅读:

  

X =< Y时,请忘记谓词的第二个子句,并统一YZ

裁员抛弃了选择点。选择点是证明树中的标记,告诉Prolog在找到解决方案后在哪里继续搜索更多解决方案。因此切割会切掉部分证明树。上面的第一个链接(here it is again)讨论了一些细节,但这个答案的很大一部分只是引用了其他人对其他地方削减的看法。

我认为带回家的消息是,一旦你在Prolog程序中进行了切割,你就强迫自己在操作上而不是声明地阅读它。为了理解证明树的哪些部分将被删除,你(程序员)必须经历这些动作,考虑条款的顺序,考虑哪些子目标可以创建选择点,考虑哪些解决方案丢失。你需要构建证明树(而不是让Prolog这样做)。

您可以使用许多技术来避免创建您不需要的选择点。然而,这是一个很大的话题。您应阅读可用材料并提出具体问题。

答案 1 :(得分:0)

您的代码的问题在于,在评估您的查询时从未达到过切割。

尝试使用规则评估目标的第一步是模式匹配。

目标 max(2,3,2) 与模式 max(X,Y,Y) 不匹配,因为模式中的第二个和第三个参数相同,并且 3 和 2 彼此不模式匹配。因此,这条规则在模式匹配阶段已经失败了,因此评估者没有达到测试 X =< Y 的程度,更不用说达到 !

但是您对切割的理解非常正确。鉴于此代码

a(X) :- b(X).
a(X) :- c(X).
b(X) :- d(X), !.
b(X) :- e(X).
c(3).
d(4).
d(5).
e(6).

和目标

?- a(X).

解释器将从第一条规则开始,尝试满足 b(X)。在这个过程中,它发现d(4)提供了一个解决方案,因此将值4绑定到X。然后开始切入,丢弃 b(X) 上的回溯,因此找不到 b(X) 的进一步解。但是,它不会删除 a(X) 上的回溯,因此如果您让 Prolog 找到另一个解决方案,那么它会通过 X = 3 规则找到 a(X) :- c(X).。如果您将第一条规则更改为 a(X) :- b(X), !.,那么它将无法找到 X = 3

虽然切割意味着没有找到 X = 5 解决方案,但如果您的查询是

?- a(5).

然后解释器将返回true。这是因为a(5)调用b(5)d(5)调用d(4)a(X)被定义为true。 services.ConfigureApplicationCookie(config => { config.Cookie.Name = "IdentityServer.Cookie"; config.LoginPath = "/Auth/Login"; config.LogoutPath = "/Auth/Logout"; }); 事实未能通过模式匹配,因此它不会像查询 @tags 时那样触发切割。

这是一个红色切割的例子(见我对 user1812457 的回答的评论)。除了破坏逻辑纯度之外,避免红色切割的一个很好的理由可能是避免这种行为导致的错误。