这里潜伏着两个主要问题:
1- 你很难在正确的地方进行统一和算术运算
2-你没有足够检查你的输入
备注 1- (is)/2
用于执行算术运算,例如,减去1
。可以但不应该用于将变量统一为已经计算过的算术表达式。应该是首选(统一)。Limit
(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 成功并返回一个解决方案时,它只能通过探索执行过程中留下的选择点来找到新的解决方案。在这里,剩下的唯一选择点是 when Limit
is 0
。所以它在这种情况下尝试第二个子句而不是第一个子句并循环直到它到达NegativeInfinity
. 可悲的是,由于到达那里的行程很长,所以它之前溢出了。这个问题的解决方案是在第二个子句中添加一个保护,指定Limit
应该大于0
或在第一个子句中添加一个cut,甚至更好:两者都做。问问你自己这样做有没有困难!