Prolog 困惑于查询和回溯

Prolog 困惑于查询和回溯,prolog,Prolog,我对使用一些规则进行查询时会发生什么感到有点困惑。 下面是我笔记中的示例代码 link(fortran, algol60). link(algol60,cpl). link(cpl, bcpl). link(bcpl, c). link(c, cplusplus). link(algol60, simula67). link(simula67, cplusplus). link(simula67, smalltalk80). path(L,M) :- %first path lin

我对使用一些规则进行查询时会发生什么感到有点困惑。 下面是我笔记中的示例代码

link(fortran, algol60).
link(algol60,cpl).
link(cpl, bcpl).
link(bcpl, c).
link(c, cplusplus).
link(algol60, simula67).
link(simula67, cplusplus).
link(simula67, smalltalk80).

path(L,M) :-   %first path
    link(L,M). %first link

path(L,M) :-   %second path
    link(L,X), %second link
    path(X,M). %third path



 | ?- path(X,bcpl).
当我们查询这个时,我们将调用第一个路径,X将被初始化为cpl,因为link(cpl,bcpl)是数据库中匹配的第一个东西。现在L=cpl,M=bcpl。 X=cpl; 然后我们继续施压


接下来会发生什么?我们叫第一条路还是第二条路?如果我们没有通过规则,我们会从第一条路径开始吗?

您需要下一个解决方案。正如您已经知道的,Prolog中的备选方案用多个子句表示

诚然,从上到下、从左到右的抽象解释不会尝试第一条路径或第二条路径/2,而是首先尝试查看是否存在另一个
链接(X,bcpl)

由于索引的原因,SWI Prolog不会尝试调用其中任何一个(它知道没有其他合适的链接/2),而是会回溯并尝试下一个路径/2(第二条规则)

这里有一个(部分)跟踪:当您看到
Redo
,这意味着它正在选择下一个可用的替代方案。括号之间的数字是调用级别,但是您可以看到,对于一些实现细节,证明不是从1开始的

?- leash(-all), trace, path(X,bcpl).
   Call: (7) path(_G2093, bcpl)
   Call: (8) link(_G2093, bcpl)
   Exit: (8) link(cpl, bcpl)
   Exit: (7) path(cpl, bcpl)
X = cpl ;
   Redo: (7) path(_G2093, bcpl)
   Call: (8) link(_G2093, _G2262)
   Exit: (8) link(fortran, algol60)
   Call: (8) path(algol60, bcpl)
   Call: (9) link(algol60, bcpl)
   Fail: (9) link(algol60, bcpl)
   Redo: (8) path(algol60, bcpl)
   Call: (9) link(algol60, _G2262)
   Exit: (9) link(algol60, cpl)
   Call: (9) path(cpl, bcpl)
   Call: (10) link(cpl, bcpl)
   Exit: (10) link(cpl, bcpl)
   Exit: (9) path(cpl, bcpl)
   Exit: (8) path(algol60, bcpl)
   Exit: (7) path(fortran, bcpl)
X = fortran ;
   Redo: (9) path(cpl, bcpl)
...
   Fail: (8) path(cplusplus, bcpl)
   Redo: (8) link(_G2093, _G2262)
   Exit: (8) link(simula67, smalltalk80)
   Call: (8) path(smalltalk80, bcpl)
   Call: (9) link(smalltalk80, bcpl)
   Fail: (9) link(smalltalk80, bcpl)
   Redo: (8) path(smalltalk80, bcpl)
   Call: (9) link(smalltalk80, _G2262)
   Fail: (9) link(smalltalk80, _G2262)
   Fail: (8) path(smalltalk80, bcpl)
   Fail: (7) path(_G2093, bcpl)
false.

您需要下一个解决方案。正如您已经知道的,Prolog中的备选方案用多个子句表示

诚然,从上到下、从左到右的抽象解释不会尝试第一条路径或第二条路径/2,而是首先尝试查看是否存在另一个
链接(X,bcpl)

由于索引的原因,SWI Prolog不会尝试调用其中任何一个(它知道没有其他合适的链接/2),而是会回溯并尝试下一个路径/2(第二条规则)

这里有一个(部分)跟踪:当您看到
Redo
,这意味着它正在选择下一个可用的替代方案。括号之间的数字是调用级别,但是您可以看到,对于一些实现细节,证明不是从1开始的

?- leash(-all), trace, path(X,bcpl).
   Call: (7) path(_G2093, bcpl)
   Call: (8) link(_G2093, bcpl)
   Exit: (8) link(cpl, bcpl)
   Exit: (7) path(cpl, bcpl)
X = cpl ;
   Redo: (7) path(_G2093, bcpl)
   Call: (8) link(_G2093, _G2262)
   Exit: (8) link(fortran, algol60)
   Call: (8) path(algol60, bcpl)
   Call: (9) link(algol60, bcpl)
   Fail: (9) link(algol60, bcpl)
   Redo: (8) path(algol60, bcpl)
   Call: (9) link(algol60, _G2262)
   Exit: (9) link(algol60, cpl)
   Call: (9) path(cpl, bcpl)
   Call: (10) link(cpl, bcpl)
   Exit: (10) link(cpl, bcpl)
   Exit: (9) path(cpl, bcpl)
   Exit: (8) path(algol60, bcpl)
   Exit: (7) path(fortran, bcpl)
X = fortran ;
   Redo: (9) path(cpl, bcpl)
...
   Fail: (8) path(cplusplus, bcpl)
   Redo: (8) link(_G2093, _G2262)
   Exit: (8) link(simula67, smalltalk80)
   Call: (8) path(smalltalk80, bcpl)
   Call: (9) link(smalltalk80, bcpl)
   Fail: (9) link(smalltalk80, bcpl)
   Redo: (8) path(smalltalk80, bcpl)
   Call: (9) link(smalltalk80, _G2262)
   Fail: (9) link(smalltalk80, _G2262)
   Fail: (8) path(smalltalk80, bcpl)
   Fail: (7) path(_G2093, bcpl)
false.

实际上,您可以使用跟踪程序自己回答您的问题。尝试键入:
?-trace.
在尝试相同的目标之前,在提示符处键入,您将看到所有调用、失败和重做-s。我已尝试遵循此操作,但我迷路了,因为我不确定第三个路径调用的是第一个路径还是第二个路径。如果您使用的是SWI Prolog,行首的数字将告诉您是否进入一个新的“框架”,即谓词的新调用。无论如何,您所调用的“第三条路径”是对谓词
path
的新调用,它有两个子句。您的“第一条”和“第二条路径”是谓词定义,而第三条“路径”实际上是一个子目标。这是一个基本的区别,我现在能想到的所有编程语言都有这个区别。实际上,你可以自己使用跟踪程序来回答你的问题。尝试键入:
?-trace.
在尝试相同的目标之前,在提示符处键入,您将看到所有调用、失败和重做-s。我已尝试遵循此操作,但我迷路了,因为我不确定第三个路径调用的是第一个路径还是第二个路径。如果您使用的是SWI Prolog,行首的数字将告诉您是否进入一个新的“框架”,即谓词的新调用。无论如何,您所调用的“第三条路径”是对谓词
path
的新调用,它有两个子句。您的“第一条”和“第二条路径”是谓词定义,而第三条“路径”实际上是一个子目标。这是一个基本的区别,我现在能想到的所有编程语言都有这个区别。因此,从您所说的,在link(cpl,bcpl)的初始匹配之后,prolog将尝试寻找其他link(X,bcpl)。但由于没有,它将失败并转到第二条路径,重做:(7)路径(_G2093,bcpl)是否正确?是的,我认为正确。尝试路径(X,Y)以查看替代链接/2扫描。因此,根据您所说的,在链接(cpl,bcpl)的初始匹配之后,prolog将尝试查找其他链接(X,bcpl)。但由于没有,它将失败并转到第二条路径,重做:(7)路径(_G2093,bcpl)是否正确?是的,我认为正确。尝试路径(X,Y)以查看备选链接/2扫描。