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

Prolog 序言:检查X是否在0到K-1的范围内,prolog,range,infinite-loop,failure-slice,successor-arithmetics,Prolog,Range,Infinite Loop,Failure Slice,Successor Arithmetics,我不熟悉prolog,我编写的每一段代码都会变成一个无限循环 我特别想看看X是否在0到K-1的范围内 range(X,X). range(X,K) :- K0 is K - 1, range(X,K0). 我在代码背后的想法是,我递减K,直到K0等于X,然后基本情况将生效。不过,我得到了一个无限循环,所以我的思维方式有些地方是错误的。我认为最简单的方法是: range(X,X). range(X,K) :- X>0, X<K-1. 我认为最简单的方法是: range(X,X).

我不熟悉prolog,我编写的每一段代码都会变成一个无限循环

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

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

我在代码背后的想法是,我递减K,直到K0等于X,然后基本情况将生效。不过,我得到了一个无限循环,所以我的思维方式有些地方是错误的。

我认为最简单的方法是:

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

我认为最简单的方法是:

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

欢迎来到Prolog的奇妙世界!在学习Prolog时,您似乎试图跳过几个步骤,但(毫不奇怪)失败了

理想情况下,你可以像书一样从家庭关系开始。然后使用扩展到自然数,然后才转到
(is)/2
。今天(也就是说,大约从1996年开始),甚至有一种比使用
(is)/2
更好的方法,即在SICStus或SWI中找到的
库(clpfd)

让我们看看你的程序会是怎样的,使用。也许
小于或等于/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
目标,使您的程序尽可能小。在任何地方。某些结果程序仍然不会终止。这些是最有趣的,因为它们是原始程序不终止的原因!它们与你的问题有直接的因果关系。因为它们比较短,所以更好。这意味着更少的阅读时间。这里有一些尝试,我将删去那些不再相关的部分

range(X,X). range(X,K) :- K0 is K - 1, false, range(X,K0). 范围(X,X)。 范围(X,K):- K0是K-1,错, 射程(X,K0)。 不,上面没有循环,所以它不能告诉我们任何事情。让我们再试一次:

range(X,X) :- false. range(X,K) :- K0 is K - 1, range(X,K0), false. 范围(X,X):-错误。 范围(X,K):- K0是K-1, 范围(X,K0),假。 这个循环已经循环了
范围(X,1)
。事实上,它是最小的故障片。有了一点经验,你就会学会不费吹灰之力地去看那些人


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

欢迎来到Prolog的奇妙世界!在学习Prolog时,您似乎试图跳过几个步骤,但(毫不奇怪)失败了

理想情况下,你可以像书一样从家庭关系开始。然后使用扩展到自然数,然后才转到
(is)/2
。今天(也就是说,大约从1996年开始),甚至有一种比使用
(is)/2
更好的方法,即在SICStus或SWI中找到的
库(clpfd)

让我们看看你的程序会是怎样的,使用。也许
小于或等于/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
目标,使您的程序尽可能小。在任何地方。某些结果程序仍然不会终止。这些是最有趣的,因为它们是原始程序不终止的原因!它们与你的问题有直接的因果关系。因为它们比较短,所以更好。这意味着更少的阅读时间。这里有一些尝试,我将删去那些不再相关的部分

range(X,X). range(X,K) :- K0 is K - 1, false, range(X,K0). 范围(X,X)。 范围(X,K):- K0是K-1,错, 射程(X,K0)。 不,上面没有循环,所以它不能告诉我们任何事情。让我们再试一次:

range(X,X) :- false. range(X,K) :- K0 is K - 1, range(X,K0), false. 范围(X,X):-错误。 范围(X,K):- K0是K-1, 范围(X,K0),假。 这个循环已经循环了
范围(X,1)
。事实上,它是最小的故障片。