Home > Blockchain >  How can I generate a list of numbers in between two parameters?
How can I generate a list of numbers in between two parameters?

Time:03-26

I am new to Prolog, and have been having some problems figuring out the syntax of the language. I want to create a method which takes 3 arguements of (X,Y,Z).

X is a list of all of the numbers in between Y and Z. I know that the base case should only return Y since Y 1 = Z. Then the recursive should keep incrementing Y until it is equal to Z while putting the numbers into a list.

Since I am new, I wanted to avoid using built-in libraries and predicates.

This is what I am working off of right now.

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

I realized a bit later that my expected results should look like this:

range(X,1,10) should return [1,2,3,4,5,6,7,8]

CodePudding user response:

Here a simple solution:

range([],A,B):-
    A > B.
range([A|T],A,B):-
    A =< B,
    A1 is A   1,
    range(T,A1,B).

First clause: if A is greater than B, the resulting list is empty ([]). Second clause: if A is less or equal than B, increment A by 1 and store the result in A1, unify the head of the list with A (see [A|T]), and recursively call the predicate with the remaining part of the list (T), A1, and B.

?- range(L,1,10).
L = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
false
?- range(L,10,1).
L = []
false

CodePudding user response:

There are multiple use cases for something like this:

  • testing that an integer lies within a given range, and
  • generating a specified sequence of integers.

This covers both ascending ranges and descending ranges, so

  • range(1,5,X) will, on backtracking, unify X with 1,2,3,4,5.
  • range(5,1,X) will, on backtracking, unify X with 5,4,3,2,1.
  • range(1,5,9) tests whether or not 9 lies within the ascending range 1-5 (it does not).
  • range(5,1,3) tests whether or not 3 lies within the descending range 5-1 (it does).
% ==========================================================
% 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) .
  • Related