我是prolog的新手,我编写的每一段代码都变成了无限循环。
我特意试图查看X是否在0到K-1的范围内。
range(X,X).
range(X,K) :- K0 is K - 1, range(X,K0).
我在代码背后的想法是我减少K直到K0等于X,然后基本情况将开始。虽然我得到一个无限循环,所以我想的方式是错误的。
答案 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这样的书,并从家庭关系开始。然后使用successor-arithmetics向自然数字扩展,然后转到(is)/2
。今天(也就是自1996年左右开始),甚至有一种比使用(is)/2
更好的方法,即在{SICStus或SWI中找到library(clpfd)
。
让我们看一下你的程序将如何使用successor-arithmetics。也许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中的终止?最好是使用failure-slice。我们的想法是,通过在您的计划中插入 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.
. %