递归函数用于遍历不进步的数字

Recursive function for going through digits not progressing

我正在尝试用一个参数做一个名为“all_even”的谓词。它将获取该参数并使用 mod() 检查它是偶数还是奇数;如果它是奇数,那么谓词应该停止工作,我认为这将通过剪切 (!) 功能来完成。

但我的递归案例似乎不起作用。当我追踪它时,我输入的数字 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 
...