1

我正在尝试制作一个 Prolog 谓词,它可以让我测试给定值是否是大于 0 的整数,并在给定变量的情况下给我一个有效的整数。现在看起来像这样:

intgr(1).
intgr(X) :- intgr(Y), X is Y+1.

这将生成所有整数,但是当用作 intgr(8) 时,它会发现它是有效的,然后永远循环。关于如何解决这个问题的任何想法?

4

2 回答 2

3

这首先是您的程序不终止的原因。为了看到这一点,我将false在您的程序中添加目标:

整数(1):-。
intgr(X) :- intgr(Y), false , X 是 Y+1

现在有趣的是以下属性。给定对您程序的任何查询,

如果这个片段(故障片)没有终止,那么你的原始程序也不会终止。

在这个片段中可能更容易看到:这个程序无法终止。该变量X仅在头部出现一次。在程序的可见部分没有进一步的引用,因此没有人关心X. 那就是:无论你把什么作为参数intgr/1,你的定义都会循环。任何事物!intgr(-1)循环,intgr(stop)循环,intgr(X)循环,intgr(1)循环。

有关故障切片以及如何使用它们的更多信息,请参阅标签

要消除问题,必须在程序的可见部分进行更改。不要看删除线部分 - 它们将无法改善终止。

我会使用length(_, N)其中包括 0。这是另一种使用方式library(clpfd)

?- X #> 0.

如果你坚持列举解决方案:

nat(0).
nat(X0) :-
   X0 #> 0,
   X1 #= X0-1,
   nat(X1).
于 2013-11-14T15:32:05.890 回答
1

为了生成自然数,您可以轻松编写尾递归(因此更节省空间)谓词。例如:

next_integer(I) :-
    next_integer(1, I).

next_integer(I, I).
next_integer(I, J) :-
    I2 is I + 1,
    next_integer(I2, J).

但请注意,已经有几个 Prolog 编译器作为内置谓词或作为库谓词提供了事实上的标准between/3谓词,它允许您枚举给定间隔内的整数。例如:

?- between(1, 3, I).
I = 1 ;
I = 2 ;
I = 3.

根据实现,您还可以使用此谓词来测试整数是否属于给定区间,而不会留下虚假的选择点。例如:

?- between(1, 3, 2).
true.

回到您的问题,您的谓词将在测试时循环回溯,因为其中没有任何内容表明您通过的参数不会通过在每次通过时继续添加而再次找到。一种解决方案是使用标准内置谓词测试参数,var/1并在参数绑定时切入第一个解决方案。例如:

next_integer(I) :-
    (   var(I) ->
        next_integer(1, I).
    ;   integer(I) ->
        next_integer(1, I),
        !
    ;   fail    % or error
    )

next_integer(I, I).
next_integer(I, J) :-
    I2 is I + 1,
    next_integer(I2, J).

希望这可以帮助。

于 2013-11-14T14:06:25.987 回答