首页 > 解决方案 > 遍历数字的递归函数不进行

问题描述

我正在尝试使用一个参数来做一个名为“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

标签: prolog

解决方案


我认为您的代码存在几个问题:

  • 当数字不是偶数时,第一个子句(您的基本情况)成功
  • 递归子句在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 
...

推荐阅读