Prolog-降序列表

Prolog-降序列表,prolog,logic-programming,Prolog,Logic Programming,我正在尝试编写一个函数-decListRange(X,List),它按降序给出范围[X-1:1]中的列表。例如- decListRange(9,列表)。 将给予- List = [8,7,6,5,4,3,2,1]. 我尝试了以下方法,但它进入了无限循环- decListRange(1,[]) :- !. decListRange(X,[H|Rest]) :- H = X-1, NextX = X - 1 ,decListRange(NextX,Rest). 你有两个问题。第一个真

我正在尝试编写一个函数-
decListRange(X,List)
,它按降序给出范围
[X-1:1]
中的列表。例如-
decListRange(9,列表)。

将给予-

List = [8,7,6,5,4,3,2,1].
我尝试了以下方法,但它进入了无限循环-

decListRange(1,[]) :- !. 
decListRange(X,[H|Rest]) :-
    H  = X-1, NextX = X - 1 ,decListRange(NextX,Rest).

你有两个问题。第一个真正的问题是您需要使用
is
而不是
=

H is X-1
这是触发算术求值所必需的。你的第二个问题不是真正的问题,但说明了一个更大的误解,即
H
NextX
是等价的。因为Prolog只有绑定,而不是像它原来那样的“可赋值”,所以您永远不应该真正需要使用相同的绑定创建两个“变量”。没有保留任何状态供您以后修改

清理这两个区域,您会得到以下结果:

decListRange(1, []) :- !.
decListRange(X, [H|Rest]) :-
  X > 1,
  H is X-1,
  decListRange(H, Rest).
编辑2:clpfd实现

:- use_module(library(clpfd)).

declist(N, L) :- N == 1, !, L = []. % green cut
declist(1, []). 
declist(N, [N1|Ns]) :- 
  N #> 1, 
  N1 #= N - 1, 
  declist(N1, Ns).
这一条在评论中有如下属性@false-notices:

?- declist(3, L).
L = [2, 1] ;
false.

?- declist(3, [2,1]).
true ;
false.

?- declist(N, [3,2,1]).
N = 4.

?- declist(N, X).
N = 1,
X = [] ;
N = 2,
X = [1] ;
N = 3,
X = [2, 1] ;
N = 4,
X = [3, 2, 1] ;
N = 5,
X = [4, 3, 2, 1] .
编辑:关于
=
之间差异的简短插曲是

在过程语言中,
=
几乎总是将特定值赋给变量的语法。在Prolog中,变量是绑定,一旦建立,就不能通过重新指定变量的不同值来直接修改它们。相反,它们更像数学和逻辑中的变量,变量“代表”有趣的值,但这些值本身基本上是不变的。在Prolog中,
=
本质上要求统一引擎建立绑定。如果你要做这样的事情:

?- name(X, Y) = name(bob, tony).
Prolog使用变量绑定进行响应:

X = bob,
Y = tony.
一旦这些绑定存在,矛盾绑定将失败,肯定绑定将成功:

?- name(X, Y) = name(bob, tony), X = bob.
X = bob,
Y = tony.

?- name(X, Y) = name(bob, tony), X = william.
false.
统一算法本身对算术一无所知。这有一个令人愉快的副作用,您可以使用任何原始表达式。例如:

?- Expr = X + 3, Z + Q = Expr.
Expr = Z+3,
X = Z,
Q = 3.
这看起来可能真的很令人惊讶。您可能认为Prolog非常聪明,可以保留表达式,因为它注意到X是一个变量或其他东西,但这也不是真的:

?- X = 4, Expr = X + 3, Z + Q = Expr.
X = 4,
Expr = 4+3,
Z = 4,
Q = 3.
从另一个角度来看,Prolog认为
+
只是另一个操作符,因此
X+3
是一个事实,就像
add(X,3)
一样,它不一定有任何特殊意义。无论您以何种方式看待它,
is/2
运算符存在,用于应用算术推理并生成一个值:

?- X = 4, Expr is X + 3.
X = 4,
Expr = 7.
请注意,Expr具有计算值,但没有原始结构:

?- X = 4, Expr is X + 3, Z + Q = Expr.
false.

在实践中,如果您需要使用算术进行大量推理,您将需要使用类似
clpfd
clpqr
的库,这取决于您对整数还是实数感兴趣。此库使您能够更轻松地执行更有趣的操作,例如指定一个方程适用于特定范围内的值并将这些值取出来。

谢谢。您能简单地解释一下bw
=
的不同之处吗?我添加了一些解释。希望有帮助@false我认为看到您的实现将是一件令人愉快和有益的事情。我确信我可以解决循环问题,但我不知道如何使decListRange(N,L)枚举。你几乎可以做到。可以直接使用库(clpfd)进行枚举。如果没有它,正确编程将是一场噩梦。想想看:许多实现没有完全正确地实现length/2。请看@false,我已经添加了该版本。我仍然得到一个虚假的错误结果,所有参数都被完全实例化。我少了一个伤口吗?