Prolog - 降序列表

时间:2013-01-17 18:46:43

标签: prolog logic-programming

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

会给 -

List = [8,7,6,5,4,3,2,1].

我尝试了以下内容,但它进入了无限循环 -

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

1 个答案:

答案 0 :(得分:2)

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

H is X-1

这是触发算术评估所必需的。你的第二个问题不是一个真正的问题,而是一个更大的误解,即HNextX是等价的。因为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提及的属性:

?- 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] .

修改:关于=is之间差异的简短插曲。

在过程语言中,=几乎总是将特定值赋给变量的语法。在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.

实际上,如果你需要用算术做很多推理,你会想要使用像clpfdclpqr这样的库,这取决于你是对整数还是实数感兴趣。这个库使您可以更轻松地完成更多有趣的事情,例如指定一个等式适用于某个范围内的值并获取这些值。