在Prolog中打印数字序列

bil*_*m25 0 prolog

我想在Prolog中创建一系列数字.因此,如果功能是print(4,3,10),它将打印4 7 10 13 16 19 22 25 28 31.第二个参数确定下一个数字,最后一个参数确定序列应停止的位置.

我有代码,但它似乎不起作用.

print(A,B,C) :- C>=0. print(A,B,C) :- D is A+B, E is C-1, print(D,B,E), write(D).

结果只显示true.

这个问题有什么解决方案吗?谢谢.

tas*_*tas 6

你快到了.你已经意识到每次你的谓词写一个数字时都必须减少计数器,所以为什么不在它变为零时停止?如果你改变了第一条规则......

print(_A,_B,0).
print(A,B,C) :-
   D is A+B,
   E is C-1,
   print(D,B,E),
   write(D).
Run Code Online (Sandbox Code Playgroud)

...你的谓词已经提供了答案:

?- seq_step_len(4,3,10).
3431282522191613107
true ;
ERROR: Out of local stack
Run Code Online (Sandbox Code Playgroud)

请注意,在非递归规则的前两个参数前面有一个下划线.这可以避免在加载源文件时出现单例警告.但是,序列不是从4开始,而是以34开头,它不以31结尾,而是以7结尾,数字之间没有空格.然后出现了这个错误ERROR: Out of local stack.后者可以通过向C>0递归规则添加目标来轻松避免.可以通过编写A而不是写入来避免错误的开始/结束编号D.要解决反转序列,可以A 递归之前编写.并且在数字之间添加空格我建议使用format/2而不是write/1.然后print2/3可能看起来像:

print2(_A,_B,0).
print2(A,B,C) :-
   C>0,                    % <- new goal
   format('~d ', [A]),     % <- format/2 instead of write/1
   D is A+B,
   E is C-1,
   print2(D,B,E).
Run Code Online (Sandbox Code Playgroud)

这产生了预期的结果:

?- print2(4,3,10).
4 7 10 13 16 19 22 25 28 31 
true ;
false.
Run Code Online (Sandbox Code Playgroud)

当你在它的时候,为什么不将序列放在列表中呢?然后你可以实际使用它,例如作为另一个谓词中的目标.拥有一个更具描述性的名称也会很好,这使得哪个论证更明显.所以让我们为序列添加一个参数,然后谓词看起来像这样:

seq_start_end_len([],_A,_B,0).
seq_start_end_len([A|As],A,B,C) :-
   C>0,
   D is A+B,
   E is C-1,
   seq_start_end_len(As,D,B,E).
Run Code Online (Sandbox Code Playgroud)

如果您碰巧使用SWI-Prolog,则可能必须输入w才能看到整个列表:

?- seq_start_end_len(Seq,4,3,10).
Seq = [4, 7, 10, 13, 16, 19, 22, 25, 28|...] [write]
Seq = [4, 7, 10, 13, 16, 19, 22, 25, 28, 31] ;
false.
Run Code Online (Sandbox Code Playgroud)

但是,如果您尝试使用后三个参数中的任何一个作为变量来查询此谓词,那么您将遇到错误:

?- seq_start_end_len(Seq,X,3,10).
ERROR: is/2: Arguments are not sufficiently instantiated
?- seq_start_end_len(Seq,4,X,10).
ERROR: is/2: Arguments are not sufficiently instantiated
?- seq_start_end_len(Seq,4,3,X).
Seq = [],
X = 0 ;
ERROR: >/2: Arguments are not sufficiently instantiated
Run Code Online (Sandbox Code Playgroud)

这是由于使用is/2>/2.您可以使用CLP(FD)来避免这些错误:

:- use_module(library(clpfd)).         % <- new

seq_start_end_len([],_A,_B,0).
seq_start_end_len([A|As],A,B,C) :-
   C#>0,                               % <- change
   D #= A+B,                           % <- change
   E #= C-1,                           % <- change
   seq_start_end_len(As,D,B,E).
Run Code Online (Sandbox Code Playgroud)

如果您现在尝试上述查询之一,您将获得许多剩余目标作为答案:

?- seq_start_end_len(Seq,X,3,10).
Seq = ['$VAR'('X'), _G1690, _G1693, _G1696, _G1699, _G1702, _G1705, _G1708, _G1711, _G1714],
'$VAR'('X')+3#=_G1690,
_G1690+3#=_G1693,
_G1693+3#=_G1696,
_G1696+3#=_G1699,
_G1699+3#=_G1702,
_G1702+3#=_G1705,
_G1705+3#=_G1708,
_G1708+3#=_G1711,
_G1711+3#=_G1714,
_G1714+3#=_G1838 ;
false.
Run Code Online (Sandbox Code Playgroud)

为了获得实际数字,您必须限制X序列中变量的范围并标记变量:

?- X in 1..4, seq_start_end_len(Seq,X,3,10), label(Seq).
X = 1,
Seq = [1, 4, 7, 10, 13, 16, 19, 22, 25, 28] ;
X = 2,
Seq = [2, 5, 8, 11, 14, 17, 20, 23, 26, 29] ;
X = 3,
Seq = [3, 6, 9, 12, 15, 18, 21, 24, 27, 30] ;
X = 4,
Seq = [4, 7, 10, 13, 16, 19, 22, 25, 28, 31] ;
false.

?- X in 1..4, seq_start_end_len(Seq,4,X,10), label(Seq).
X = 1,
Seq = [4, 5, 6, 7, 8, 9, 10, 11, 12, 13] ;
X = 2,
Seq = [4, 6, 8, 10, 12, 14, 16, 18, 20, 22] ;
X = 3,
Seq = [4, 7, 10, 13, 16, 19, 22, 25, 28, 31] ;
X = 4,
Seq = [4, 8, 12, 16, 20, 24, 28, 32, 36, 40] ;
false.

?- X in 1..4, seq_start_end_len(Seq,4,3,X), label(Seq).
X = 1,
Seq = [4] ;
X = 2,
Seq = [4, 7] ;
X = 3,
Seq = [4, 7, 10] ;
X = 4,
Seq = [4, 7, 10, 13] ;
false.
Run Code Online (Sandbox Code Playgroud)

使用CLP(FD)版本,您还可以询问更多常规查询,例如长度为4到6的序列,数字范围是1到10?:

?- Len in 4..6, seq_start_end_len(Seq,S,E,Len), Seq ins 1..10, label(Seq).
Len = 4,
Seq = [1, 1, 1, 1],
S = 1,
E = 0 ;
Len = 4,
Seq = [1, 2, 3, 4],
S = E, E = 1 ;
Len = 4,
Seq = [1, 3, 5, 7],
S = 1,
E = 2 ;
.
.
.
Len = 6,
Seq = [9, 9, 9, 9, 9, 9],
S = 9,
E = 0 ;
Len = 6,
Seq = [10, 9, 8, 7, 6, 5],
S = 10,
E = -1 ;
Len = 6,
Seq = [10, 10, 10, 10, 10, 10],
S = 10,
E = 0 ;
false.
Run Code Online (Sandbox Code Playgroud)

你获得了所有80种可能性.请注意,名称反映了CLP(FD)谓词的关系性质.

  • 比我的答案解释得更好,但我的确允许你一些额外的查询,因为没有使用'是':).此外,我认为我的选择点开放较少..但我的某些时候会循环寻找一般查询不存在的答案. (3认同)
  • @ user27815:你对使用`is/2`的后果是绝对正确的.我还在编写CLP(FD)部分的答案,以使谓词更通用,当我看到你已经发布了答案,所以我匆匆忙忙.:-P现在我的帖子已经完成了.旁注:我非常喜欢你的版本中`length/2`和`maplist/2`的组合,所以s(X)就是这样.;-) (2认同)