Prolog在定义自然数时遵循哪些步骤?

Prolog在定义自然数时遵循哪些步骤?,prolog,successor-arithmetics,Prolog,Successor Arithmetics,我正在学习如何用Prolog编程,我找到了下一个定义自然数及其和的程序: sum( succ( X ), Y, succ( Z )) :- sum( X, Y, Z ). sum( 0, X, X ). ?- sum( succ( succ(0)), succ( succ( succ(0))), Answer ). Answer = succ( succ( succ( succ( succ(0))))) 发现 问题是,我正在与这个程序的执行流作斗争。说实话,我不知道它是干什么的。Prolog如

我正在学习如何用Prolog编程,我找到了下一个定义自然数及其和的程序:

sum( succ( X ), Y, succ( Z )) :- sum( X, Y, Z ).
sum( 0, X, X ).
?- sum( succ( succ(0)), succ( succ( succ(0))), Answer ).
Answer = succ( succ( succ( succ( succ(0)))))
发现

问题是,我正在与这个程序的执行流作斗争。说实话,我不知道它是干什么的。Prolog如何计算答案的值?Prolog遵循哪些步骤来找到答案的值


提前感谢。

对于这样一个简单的程序,trace/0这是正确的选择/1允许控制调试器接口,这对新手来说并不完全明显:

21 ?- leash(-all),trace.
true.

[trace] 22 ?- sum( succ( succ(0)), succ( succ( succ(0))), Answer ).
   Call: (6) sum(succ(succ(0)), succ(succ(succ(0))), _G710)
   Call: (7) sum(succ(0), succ(succ(succ(0))), _G789)
   Call: (8) sum(0, succ(succ(succ(0))), _G791)
   Exit: (8) sum(0, succ(succ(succ(0))), succ(succ(succ(0))))
   Exit: (7) sum(succ(0), succ(succ(succ(0))), succ(succ(succ(succ(0)))))
   Exit: (6) sum(succ(succ(0)), succ(succ(succ(0))), succ(succ(succ(succ(succ(0))))))
Answer = succ(succ(succ(succ(succ(0))))).

您可以看到,您的程序对第一个参数执行有界递归搜索,将其与标记为6,7的第一个子句调用或标记为8的第二个子句调用统一起来。

这有助于理解Prolog在计算现有谓词或设计新谓词时是如何操作的。进行查询时,例如:

sum( succ(succ(0)), succ(succ(succ(0))), Answer ).
Prolog将查找与sum_u、u、u和/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)
请注意,即使Z还没有被指定一个具体的值,Answer的值仍然是succZ。现在我们遵循规则,它将查询,sumX,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'来区分它与sumsuc0中的另一个变量Z,succ0,Z,因为它与头部中用于求和…,succZ的变量不同。这就像在C中有一个函数声明为int fx{return 2*x;},然后从某处用另一个局部变量x调用它,这个名称x在两个不同的地方使用,代表两个不同的变量

然后我们可以再次执行下一个递归查询sumX,Y,Z',它变成:

sum( 0, succ(succ(succ(0))), Z' )
     |    |                  |
     X    Y                  Z'
此递归查询与规则1不匹配,因为第一个参数0与succX不匹配。但是,它符合规则2:

    0 = 0
    X = succ(succ(succ(0)))
(C) X = Z'
现在X=succ0,所以Z'=succ0。由于此规则中没有更多的查询,因此它最终会成功返回到查询它的位置。将其返回到上面的B:

Z = succ(Z') = succ(succ(succ(succ(0))))
并将其返回到一个:

Answer = succ(Z) = succ(succ(succ(succ(succ(0)))))

就在这里。使用@capelical提到的跟踪功能,您可以在Prolog解释器中观察这些连续步骤,并跟踪变量的实例化。

Prolog的求值过程是将给定查询匹配到程序规则的头部,然后在匹配替换下继续匹配规则的主体。选择规则时,其变量将统一重命名,以实现唯一性:

(1) sum( succ( X ), Y, succ( Z )) :- sum( X, Y, Z ). (2) sum( 0, X, X ). ?- sum( succ( succ(0)), succ( succ( succ(0))), Answer ). (1) -> sum( succ( X1 ), Y1 , succ( Z1 )) :- sum( X1, Y1, Z1 ). %% X1 = succ(0), Y1 = succ( succ( succ(0))), succ(Z1) = Answer. %% -? sum( X1, Y1, Z1 ). -? sum( succ( 0 ), Y1, Z1 ). (1) -> sum( succ( X2 ), Y2, succ( Z2 )) :- sum( X2, Y2, Z2 ). %% X2 = 0, Y2 = Y1, succ(Z2) = Z1. %% -? sum( X2, Y2, Z2 ). -? sum( 0, Y2, Z2 ). (2) -> sum( 0, X3, X3 ). %% DONE. %% %% X3 = Y2, X3 = Z2. %% 从这里开始,回答=succZ1=succsuccz2=succsuccx3=succsuccy2=succsuccy1=succsuccsuccsucc0