Prolog:检查X是否在0到K-1的范围内

时间:2014-12-04 10:51:54

标签: prolog range infinite-loop failure-slice

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

我特意试图查看X是否在0到K-1的范围内。

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

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

3 个答案:

答案 0 :(得分: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.

答案 1 :(得分:2)

欢迎来到Prolog的奇妙世界!在学习Prolog时,你似乎试图跳过几个步骤,并且(不是非常令人惊讶地)失败了。

理想情况下,你会选择像Art of Prolog这样的书,并从家庭关系开始。然后使用向自然数字扩展,然后转到(is)/2。今天(也就是自1996年左右开始),甚至有一种比使用(is)/2更好的方法,即在{SICStus或SWI中找到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.

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

继承者算术依赖于自然数。但是你使用了包含这些负数的整数。对于负数,数字不再是well ordered(有根据的,或Noetherian),并且您直接经历了这种后果。所以坚持自然数字!它们都是天然的,不含任何人工负面成分。谁说"God made the integers, all else is the work of man."一定是错的。

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

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

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

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

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

这个已经为range(X,1)循环。实际上,它是最小的故障切片。通过一些经验,您将学会毫不费力地看到它们。

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

答案 2 :(得分: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.
  .                   %