理解Prolog中的列表和递归

3

我在Prolog思考时遇到了困难。以下语句有何错误:

numberList([], 0).
numberList([H|T], Limit) :-
    H is Limit,
    numberList(T, Limit - 1).

I would like

?- numberList(X,Limit).

对于给定的界限值,即[Limit, Limit-1 ... 1]是唯一的解决方案。

?- numberList(X, 100).

这段代码将会得到X = [100, 99, 98, ..., 1].

我猜测我的理解还有些不对,才导致了这段代码无法正常运行。我并不是在寻求解决方案,只是想知道为什么我的第一个尝试是错误的。


简短回答:?- A-1 = 0. 失败了。 ?- A-1 is 0. 也失败了。 ?- length(X,5),X=[5|_T],append(_T,[_],_Z),maplist(succ,_Z,X). 可以达到你想要的效果。 - Will Ness
2个回答

3
这里有两个主要问题:
1- 你在获取统一和算术运算的正确位置时遇到困难。
2- 你没有充分检查输入。
关于1- 备注:(is)/2用于执行算术运算,在这里,例如从Limit中减去1。可以使用(is)/2将变量与已经评估的算术表达式相统一,但不应该这样做。应优先考虑(=)/2(统一)。
关于2- 备注:即使您确定了运算符,程序也会进入循环。稍后再详细介绍。
仅通过自己更改运算符并不能获得太多益处,因此这是正确的方法:
numberList([], 0).
numberList([Limit|T], Limit) :-
    NewLimit is Limit - 1,
    numberList(T, NewLimit).

在这里你可以看到我在第二个从句的头部隐含地使用了统一性,换句话说,另一种表达方式是:

numberList([], 0).
numberList([H|T], Limit) :-
    H = Limit,
    NewLimit is Limit - 1,
    numberList(T, NewLimit).

但是,现在你可以通过尝试这个程序来看到,它能够找到正确的解决方案,但如果你使用分号请求另一个解决方案,它会进入循环。

对于初学者来说,原因可能更难以发现:当 Prolog 成功并返回解决方案时,它只能通过探索执行期间留下的选择点来找到新的解决方案。这里,唯一剩下的选择点是当 Limit0 时。因此,在这种情况下,它尝试第二个子句而不是第一个子句,并一直循环直到达到 NegativeInfinity。不幸的是,由于旅程相当漫长,它会在溢出之前结束。解决此问题的方法是添加一个保护条件到第二个子句中,指定 Limit 应大于 0,或者在第一个子句中添加一个切割,甚至更好的方法是两者都做。如果你自己做起来有困难,请问一下!


如果你遇到了困难,请毫不犹豫地再次发问!Prolog 对于新手来说有时可能会很棘手 :p - m09
2
好的,我读了几个例子,它们似乎在说:“嘿,这是如此直观,你的母亲都能做到……”我差点不得不问她。 - Matt Esch
仅在第一个子句中使用剪枝是不起作用的:numberList(_,-1)numberList(L,1.5)。为什么要使用任何剪枝呢?为什么不使用library(clpfd)呢? - false
我并没有真正建议单独使用“切割”解决方案,所以我不会在这个问题上再发表评论。对于切割,如果所需的输入格式是(-,+),那么可以理解,否则这是一个坏主意。但是,正如你提到的,去掉切割并不能解决问题,在这里,我们必须使用除基本算术之外的其他方法来获得多路谓词。 - m09

0
"Limit - 1"被认为是一个函数调用,在C语言和类似的语言中可以工作。它要求/命令Prolog“找一个减法函数,用Limit变量和1调用它”。它要求Prolog将"Limit - 1"理解为函数调用的结果,但是Prolog将"Limit - 1"理解为一个复合术语subtract(Limit,1),它是一阶逻辑中的谓词。
"H is Limit"也被认为是一个函数调用。
Prolog没有函数(???),我认为这个说法对于C语言的人来说是一个大障碍。与函数不同(如C语言和数学中一样),Prolog有谓词(如谓词逻辑、一阶逻辑等)。
函数是一条命令,命令微处理器执行操作。而谓词向微处理器呈现数据,使其“以微处理器的眼睛看到”,向微处理器展示数据以感知。
谓词描述了世界的一部分,描述了该世界中对象之间的某些关系,微处理器试图验证这些关系。微处理器试图证明这些关系在它的知识中确实存在。这些关系可以在它的知识中多次存在,因此微处理器可以返回多个结果(也称为非确定性)。

Prolog 是一种极好的编程语言,或许我应该说它是一种极好的描述语言、模式识别语言和推理/演绎语言(进行简单的推理/演绎,而不是某种“人工智能”,推理/演绎类似于数字电子逻辑门)。以前我是一名热衷于 Visual Studio 的程序员,但现在已经学习了几年 Prolog。

C 等语言用于指令控制,而 Prolog 等语言则用于描述。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接