它有助于理解 Prolog 在找出现有谓词或设计新谓词时的操作方式。当您进行如下查询时:
sum( succ(succ(0)), succ(succ(succ(0))), Answer ).
Prolog 将查找匹配的事实和规则sum(_, _, _)
( sum/3
) 并选择第一个匹配的。现行规则如下:
(1) sum( succ(X), Y, succ(Z) ) :- sum( X, Y, Z ).
(2) sum( 0, X, X ).
如果您查看查询,它显然与规则 #1 的模式相匹配。请记住,在 Prolog 中,变量可以实例化为任何类型的术语,并且同名的变量是统一的(实例化为相同的值)。当 Prolog 将规则 #1 的“头部”与查询统一时,它通过统一变量来实现,如下所示:
X = succ(0)
Y = succ(succ(succ(0)))
(A) Answer = succ(Z)
请注意,即使尚未绑定(分配具体值) ,它Answer
也具有该值。现在我们遵循将查询的规则,这将是查询:succ(Z)
Z
sum(X, Y, Z)
sum( succ(0), succ(succ(succ(0))), Z )
| | |
X Y Z
Prolog 现在将再次从顶部开始,因为这是对sum/3
. 就像第一次一样,它使用以下统一匹配规则 #1:
X = 0
Y = succ(succ(succ(0)))
(B) Z = succ(Z')
我在Z'
上面使用它来将它与 中的其他变量区分开来Z
,sum(succ(0), succ(succ(succ(0))), Z)
因为它Z
与头部中使用的变量不同sum(..., succ(Z))
。这就像如果您在 C 中声明了一个函数,int f(x) { return 2*x; }
并且您从某个地方使用另一个局部变量调用它x
,该名称x
在两个不同的地方使用并代表两个不同的变量)。
然后我们可以再次遵循下一个递归查询sum(X, Y, Z')
,它变成:
sum( 0, succ(succ(succ(0))), Z' )
| | |
X Y Z'
此递归查询与规则 #1 不匹配,因为第一个参数0
不匹配succ(X)
。但是,它符合规则 #2:
0 = 0
X = succ(succ(succ(0)))
(C) X = Z'
现在X = succ(succ(succ(0)))
如此Z' = succ(succ(succ(0)))
。由于此规则中没有更多查询,因此它最终成功返回到查询的位置。回到上面的(B):
Z = succ(Z') = succ(succ(succ(succ(0))))
并将其返回到(A):
Answer = succ(Z) = succ(succ(succ(succ(succ(0)))))
你有它。使用trace
@CapelliC 提到的工具,您可以看到这些连续步骤发生在 Prolog 解释器中并遵循变量的实例化。