prolog - 遍历数字的递归函数不进行
问题描述
我正在尝试使用一个参数来做一个名为“all_even”的谓词。它将采用该参数并使用 mod() 检查它是偶数还是奇数;如果它很奇怪,那么谓词应该停止工作,我认为这将由 cut (!) 功能完成。
但似乎我的递归案例似乎不起作用。当我追踪它时,我输入的数字 2968 并没有改变,但最终会被一些奇怪的数字覆盖,从而破坏了整个过程。
对于上下文,这是我当前的代码:
all_even(X) :- mod(X,2)\==0.%base case
all_even(X) :- mod(X,2)=:=0,
all_even(X1), X1 is X // 10. %recursive case
这是追踪反馈
Call:all_even(2968)
Call:2968 mod 2\==0
Exit:2968 mod 2\==0
Exit:all_even(2968)
1true
Redo:all_even(2968)
Call:2968 mod 2=:=0
Exit:2968 mod 2=:=0
Call:all_even(_5638)
Call:_5638 mod 2\==0
Exit:_5638 mod 2\==0
Exit:all_even(_5638)
Call:_5638 is 2968//10
Exit:296 is 2968//10
Exit:all_even(2968)
2true
Redo:all_even(_5638)
Call:_5638 mod 2=:=0
Exception:_5638 mod 2=:=0
Arguments are not sufficiently instantiated
解决方案
我认为您的代码存在几个问题:
- 当数字不是偶数时,第一个子句(您的基本情况)成功
- 递归子句在
all_even(X1)
没有先计算的情况下调用X1
,因此稍后在进行算术运算时,它会给您一个异常,即参数没有充分实例化。
所以你应该首先计算X1
然后进行递归调用:
all_even(X) :-
X \= 0,
mod(X,2)=:=0,
X1 is X // 10,
all_even(X1) . %recursive case
all_even(0). %base case
此过程不能用作生成器,因为它无法处理未绑定的变量。为此,您可以使用 clp(FD):
all_even(0). %base case
all_even(X) :-
X #\= 0,
0 #= X mod 2,
X1 #= X // 10,
all_even(X1) . %recursive case
样品运行:
?- all_even(X), label([X]).
X = 0 ;
X = -8 ;
X = -6 ;
X = -4 ;
X = -2 ;
X = 2 ;
X = 4 ;
X = 6 ;
X = 8 ;
X = -88 ;
X = -86
...