我是具有命令式编程背景的 Prolog 初学者。在解决这个网站的作业时,我遇到了两个练习:第一个是关于查找列表的第 k 个元素,第二个是关于查找列表的长度。这些是经典的列表处理问题,解决方案非常简单,对于像我这样的初学者也是如此。我无法理解的是(显然)内置is/2
谓词的不同用法。就我而言,这个谓词迫使 Prolog 进行算术计算,并可能将结果分配给左侧项。我被告知要注意的是,尽管可以在右侧使用变量,但必须在评估时使用无变量项来实例化这些变量。
对于第一个练习,建议的解决方案如下:
element_at(X,[X|_],1).
element_at(X,[_|L],K) :- K > 1, K1 is K - 1, element_at(X,L,K1).
并且使用的方式is
对我来说很有意义:因为K
作为参数提供,K1
可以立即评估并作为递归调用中的新参数提供。
通过编写第二个练习的解决方案,即查找列表长度,我得出以下结论:
my_length([], 0).
my_length([_|L], K) :- K is K1 + 1, my_length(L, K1).
并由 Prolog 通知“参数没有充分实例化”。
正确的解决方案原来是这个:
my_length([], 0).
my_length([_|L], K) :- my_length(L, K1), K is K1 + 1.
在这种情况下,递归调用是在通过评估 K之前is
进行的。在之前的练习中,它是在评估之后进行K is K-1
的。
我想我误解了一些关键概念。什么情况下is/2
必须在递归调用之前使用,另一方面,什么时候必须在递归调用之后使用?为什么会这样?
感谢任何帮助和解释(我使用的是 SWI-Prolog 7.6.4)。