我正在阅读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
的建议解决方案?
答案 0 :(得分:3)
另请参阅this answer和this question。
我应该如何阅读上述max / 3的建议解决方案?
max(X,Y,Z):- X =< Y, !, Y = Z.
max(X,Y,X).
您可以按如下方式阅读:
当
X =< Y
时,请忘记谓词的第二个子句,并统一Y
和Z
。
裁员抛弃了选择点。选择点是证明树中的标记,告诉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 的回答的评论)。除了破坏逻辑纯度之外,避免红色切割的一个很好的理由可能是避免这种行为导致的错误。