1

我是 prolog 的新手,我写的每一段代码都会变成一个无限循环。

我特别想看看 X 是否在 0 到 K - 1 的范围内。

range(X,X).
range(X,K) :- K0 is K - 1, range(X,K0).

我在代码背后的想法是我递减 K 直到 K0 等于 X,然后基本情况将开始。虽然我得到了一个无限循环,所以我的想法是错误的。

4

3 回答 3

2

欢迎来到 Prolog 的奇妙世界!在学习 Prolog 时,您似乎试图跨越几个步骤,并且(并不奇怪)失败了。

理想情况下,你拿一本像《序言艺术》这样的书,从家庭关系开始。向自然数扩展,然后才转到(is)/2。今天,(也就是说,大约从 1996 年开始)甚至有比使用SICStus 或 SWI 中(is)/2的方法更好的方法。library(clpfd)

所以让我们看看你的程序会如何,使用。也许less_than_or_equal/2会是一个更好的名字:

less_than_or_equal(N,N).
less_than_or_equal(N,s(M)) :-
   less_than_or_equal(N,M).

?- less_than_or_equal(N,s(s(0))).
N = s(s(0)) ;
N = s(0) ;
N = 0.

它开箱即用!没有任何循环。那么出了什么问题呢?

后继算术依赖于自然数。但是您使用的整数也包含这些负数。对于负数,数字不再是有序的(有根据的,或诺特式的),你直接体验到了这种后果。所以坚持自然数!它们都是纯天然的,不含任何人为的负面成分。谁说“上帝创造了整数,其他一切都是人的工作”。一定是错的。

但现在回到你的程序。为什么它不终止?毕竟,你找到了答案,所以它不是完全错误的。不是吗?您试图将您在面向命令的语言中学到的控制流概念重新应用到 Prolog。好吧,Prolog 有两个相对独立的控制流,还有更多令人惊讶的东西,比如在运行时出现的实变量 (TM),在 Java 或 C# 中没有直接对应物。所以这个映射不起作用。当你称这个事实为“基本情况”时,我有点怀疑。您可能的意思是它是“终止条件”。但事实并非如此。

那么我们如何才能轻松地理解 Prolog 中的终止呢?最好的方法是使用false我们的想法是,我们将通过在您的程序中插入目标来尝试使您的程序尽可能小。在任何地方。某些生成的程序仍然不会终止。这些是最有趣的,因为它们是不终止原始程序的原因!它们立即与您的问题有因果关系。而且它们更好,因为它们更短。这意味着更少的阅读时间。这里有一些尝试,我将删除不再相关的部分。

范围(X,X)。
范围(X,K):-
   K0 是 K - 1, false ,
    range(X,K0)

不,上面没有循环,所以它不能告诉我们任何事情。让我们再试一次:

范围(X,X):-。 范围(X,K):- K0 是 K - 1, 范围(X,K0),

这个range(X,1)已经循环了。事实上,它是最小故障片。有了一点经验,您将学会毫不费力地看到那些。

我们必须更改可见部分中的某些内容以使其终止。例如,您可以添加K > 0或执行@Shevliaskovic 建议的操作。

于 2014-12-04T16:32:02.440 回答
2

我相信最简单的方法是:

range(X,X).
range(X,K) :- X>0, X<K-1.

这是我的结果:

6 ?- range(4,4).
true .

7 ?-  range(5,8).
true.

8 ?- range(5,4).
false.
于 2014-12-04T11:17:24.823 回答
0

正如已经指出的那样,如果您只想验证X位于指定域内的简单方法是只检查条件:

range(X,K) :- X >= 0 , X < K .

否则,如果您希望自己range/2具有生成性,则可以使用内置的between/3

range(X,K) :- integer(K) , K1 is K-1 , between(0,K1,X).

如果您的序言没有between/3,这是一个非常简单的实现:

%
% the classic `between/3` wants the inclusive lower and upper bounds
% to be bound. So we'll make the test once and use a helper predicate.
%
between(Lo,Hi,N) :-
  integer(Lo),
  integer(Hi),
  _between(Lo,Hi,N)
  .

_between(Lo,Hi,Lo) :- % unify the lower bound with the result
  Lo =< Hi            % - if we haven't yet exceeded the inclusive upper bound.
  .                   %
_between(Lo,Hi,N)  :- % otherwise...
  Lo < Hi ,           % - if the lower bound is less than the inclusive upper bound
  L1 is Lo+1 ,        % - increment the lower bound
  _between(L1,Hi,N)   % - and recurse down.
  .                   %
于 2014-12-04T19:16:43.690 回答