如何生成两个参数之间的数字列表?
How can I generate a list of numbers in between two parameters?
我是 Prolog 的新手,在理解该语言的语法时遇到了一些问题。我想创建一个方法,该方法接受 (X,Y,Z) 的 3 个参数。
X 是 Y 和 Z 之间所有数字的列表。我知道基本情况应该只有 return Y,因为 Y+1 = Z。然后递归应该继续递增 Y 直到它将数字放入列表时等于 Z。
因为我是新手,所以我想避免使用内置库和谓词。
这就是我现在正在做的事情。
range(X,Y,Z):-
%If Y + 1 == Z, X is just Y
range(X,Y,Z) :-
Y =< Z,
D is Y+1,
range(X,D,Z).
%use recursion to go from Y to Z, then collect it in X
后来我意识到我的预期结果应该是这样的:
range(X,1,10) should return [1,2,3,4,5,6,7,8]
这里有一个简单的解决方案:
range([],A,B):-
A > B.
range([A|T],A,B):-
A =< B,
A1 is A + 1,
range(T,A1,B).
第一个子句:如果 A
大于 B
,则结果列表为空 ([]
)。第二个子句:如果 A
小于或等于 B
,则将 A
递增 1
并将结果存储在 A1
中,将列表的头部与A
(参见[A|T]
),并用列表的剩余部分(T
)、A1
和B
.[=25递归调用谓词=]
?- range(L,1,10).
L = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
false
?- range(L,10,1).
L = []
false
像这样的东西有多个用例:
- 测试整数是否在给定范围内,并且
- 正在生成指定的整数序列。
这包括上升范围和下降范围,所以
range(1,5,X)
将在回溯时将 X 与 1,2,3,4,5 统一。
range(5,1,X)
将在回溯时将 X 与 5,4,3,2,1 统一。
range(1,5,9)
测试 9
是否在升序范围 1-5 内(不在)。
range(5,1,3)
测试 3
是否在降序范围 5-1 内(确实如此)。
% ==========================================================
% range/3: Tests that Z lies with the range X-Y,
% or generates the sequence of integers X-Y.
% Both ascending ranges (1-5) and descending ranges (5-1)
% are supported. X and Y must both be integers. Z must be
% either an integer or an unbound variable.
% ==========================================================
range( X , Y , Z ) :-
integer(X),
integer(Y),
range0(X,Y,Z).
% ==========================================================
% Private (helper) predicates)
% ==========================================================
% --------------------------
% range0/3: Traffic director
% --------------------------
range0( X , Y , Z ) :- integer(Z), !, range1(X,Y,Z) .
range0( X , Y , Z ) :- var(Z), !, range2(X,Y,Z) .
% ----------------------------------
% range1/3: Z is bound to an integer
% ----------------------------------
range1(Lo,Hi,N) :- N >= Lo, N =< Hi, !.
range1(Hi,Lo,N) :- N >= Lo, N =< Hi, !.
% --------------------------------------------
% range2/3: Z is unbound. Generate a sequence.
% --------------------------------------------
range2(X,Y,N) :- X =< Y, !, range_asc(Lo,Hi,N) .
range2(X,Y,N) :- X > Y, !, range_dsc(Lo,Hi,N) .
% --------------------------------------------------------
% range_asc/3: Generates an ascending sequence of integers
% --------------------------------------------------------
range_asc( Hi , Hi , Hi ) :- !.
range_asc( Lo , _ , Lo ) .
range_asc( Lo , Hi , N ) :- L1 is Lo+1, range_asc(L1,Hi,N) .
% --------------------------------------------------------
% range_dsc/3: Generates a descending sequence of integers
% --------------------------------------------------------
range_dsc( Lo , Lo , Lo ) :- !.
range_dsc( Hi , _ , Hi ) .
range_dsc( Hi , Lo , N ) :- H1 is Hi-1, range_dsc(H1,Lo,N) .
我是 Prolog 的新手,在理解该语言的语法时遇到了一些问题。我想创建一个方法,该方法接受 (X,Y,Z) 的 3 个参数。
X 是 Y 和 Z 之间所有数字的列表。我知道基本情况应该只有 return Y,因为 Y+1 = Z。然后递归应该继续递增 Y 直到它将数字放入列表时等于 Z。
因为我是新手,所以我想避免使用内置库和谓词。
这就是我现在正在做的事情。
range(X,Y,Z):-
%If Y + 1 == Z, X is just Y
range(X,Y,Z) :-
Y =< Z,
D is Y+1,
range(X,D,Z).
%use recursion to go from Y to Z, then collect it in X
后来我意识到我的预期结果应该是这样的:
range(X,1,10) should return [1,2,3,4,5,6,7,8]
这里有一个简单的解决方案:
range([],A,B):-
A > B.
range([A|T],A,B):-
A =< B,
A1 is A + 1,
range(T,A1,B).
第一个子句:如果 A
大于 B
,则结果列表为空 ([]
)。第二个子句:如果 A
小于或等于 B
,则将 A
递增 1
并将结果存储在 A1
中,将列表的头部与A
(参见[A|T]
),并用列表的剩余部分(T
)、A1
和B
.[=25递归调用谓词=]
?- range(L,1,10).
L = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
false
?- range(L,10,1).
L = []
false
像这样的东西有多个用例:
- 测试整数是否在给定范围内,并且
- 正在生成指定的整数序列。
这包括上升范围和下降范围,所以
range(1,5,X)
将在回溯时将 X 与 1,2,3,4,5 统一。range(5,1,X)
将在回溯时将 X 与 5,4,3,2,1 统一。range(1,5,9)
测试9
是否在升序范围 1-5 内(不在)。range(5,1,3)
测试3
是否在降序范围 5-1 内(确实如此)。
% ==========================================================
% range/3: Tests that Z lies with the range X-Y,
% or generates the sequence of integers X-Y.
% Both ascending ranges (1-5) and descending ranges (5-1)
% are supported. X and Y must both be integers. Z must be
% either an integer or an unbound variable.
% ==========================================================
range( X , Y , Z ) :-
integer(X),
integer(Y),
range0(X,Y,Z).
% ==========================================================
% Private (helper) predicates)
% ==========================================================
% --------------------------
% range0/3: Traffic director
% --------------------------
range0( X , Y , Z ) :- integer(Z), !, range1(X,Y,Z) .
range0( X , Y , Z ) :- var(Z), !, range2(X,Y,Z) .
% ----------------------------------
% range1/3: Z is bound to an integer
% ----------------------------------
range1(Lo,Hi,N) :- N >= Lo, N =< Hi, !.
range1(Hi,Lo,N) :- N >= Lo, N =< Hi, !.
% --------------------------------------------
% range2/3: Z is unbound. Generate a sequence.
% --------------------------------------------
range2(X,Y,N) :- X =< Y, !, range_asc(Lo,Hi,N) .
range2(X,Y,N) :- X > Y, !, range_dsc(Lo,Hi,N) .
% --------------------------------------------------------
% range_asc/3: Generates an ascending sequence of integers
% --------------------------------------------------------
range_asc( Hi , Hi , Hi ) :- !.
range_asc( Lo , _ , Lo ) .
range_asc( Lo , Hi , N ) :- L1 is Lo+1, range_asc(L1,Hi,N) .
% --------------------------------------------------------
% range_dsc/3: Generates a descending sequence of integers
% --------------------------------------------------------
range_dsc( Lo , Lo , Lo ) :- !.
range_dsc( Hi , _ , Hi ) .
range_dsc( Hi , Lo , N ) :- H1 is Hi-1, range_dsc(H1,Lo,N) .