这里有两个主要问题:
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 成功并返回解决方案时,它只能通过探索执行期间留下的选择点来找到新的解决方案。这里,唯一剩下的选择点是当 Limit
是 0
时。因此,在这种情况下,它尝试第二个子句而不是第一个子句,并一直循环直到达到 NegativeInfinity
。不幸的是,由于旅程相当漫长,它会在溢出之前结束。解决此问题的方法是添加一个保护条件到第二个子句中,指定 Limit
应大于 0
,或者在第一个子句中添加一个切割,甚至更好的方法是两者都做。如果你自己做起来有困难,请问一下!
?- A-1 = 0.
失败了。?- A-1 is 0.
也失败了。?- length(X,5),X=[5|_T],append(_T,[_],_Z),maplist(succ,_Z,X).
可以达到你想要的效果。 - Will Ness