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 not9
lies within the ascending range 1-5 (it does not).range(5,1,3)
tests whether or not3
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) .