Implementing a `range` predicate

I’m trying to implement a ‘range’ predicate and got stuck

range(_,0, []) :- !.
range(From, Len, R) :- 
    From2 #= (From + 1),
    Len2 #= (Len - 1),
    range(From2, Len2, R2),
    R = [From|R2].

?- range(From,Length,[3,4,5,6])false

I was expecting : From = 3, Length = 4

Could anyone help me with this ?

Thank You

Also, I think the first statement should instead be

range(_, 0, []).

that’s why it gives false.

1 Like

Directory: C:/Users/Groot
File: example.pl

:- module(example,
    [
        range/3
    ]).

range(From,Length,List) :-
    is_of_type(nonneg,From),
    is_of_type(nonneg,Length),
    var(List),
    !,
    range_(From,Length,List).

range(From,Length,List) :-
    var(From),
    var(Length),
    ground(List),
    !,
    List = [From|_],
    length(List,Length).

range_(_,0,[]) :- !.
range_(Current,Length0,[Current|T]) :-
    !,
    Length is Length0 - 1,
    Next is Current + 1,
    range_(Next,Length,T).

Example run

Welcome to SWI-Prolog (threaded, 64 bits, version 8.5.5)

?- working_directory(_,'C:/Users/Groot').
true.

?- [example].
true.

?- range(From,Length,[3,4,5,6]).
From = 3,
Length = 4.

?- range(3,4,L).
L = [3, 4, 5, 6].
1 Like
% Arguments: List of incrementing numbers, first number, length
incrementing_list([H|T], H, Len) :-
    incrementing_list_(T, H, 1, Len).

incrementing_list_([], _, LenUpto, Len) :-
    % Improve termination
    (var(Len) -> LenUpto = Len ; LenUpto =:= Len, !).
incrementing_list_([H|T], Prev, LenUpto, Len) :-
    % Prevent infinite loop: ?- incrementing_list(Lst, 3, 3).
    num_lt_numvar(LenUpto, Len),
    H is Prev + 1,
    LenUpto1 is LenUpto + 1,
    incrementing_list_(T, H, LenUpto1, Len).


num_lt_numvar(Num, NumVar) :-
    (var(NumVar) -> true ; Num < NumVar).

Is general, with proper termination:

?- incrementing_list(Lst, 3, N).
Lst = [3],
N = 1 ;
Lst = [3,4],
N = 2 ;
Lst = [3,4,5],
N = 3 ;

?- incrementing_list([3, Second, Third, Last], First, Len).
Second = Len, Len = 4,
Third = 5,
Last = 6,
First = 3.

?- incrementing_list(Lst, 1, 2).
Lst = [1,2].

?- incrementing_list([3, 4, 5, 6], First, Len).
First = 3,
Len = 4.
1 Like

Sorry I did not see the tag clpfd

Here is a clpfd version. Not much different.

Directory: C:/Users/Groot
File: example.pl

:- use_module(library(clpfd)).

range(From,Length,List) :-
    is_of_type(nonneg,From),
    is_of_type(nonneg,Length),
    var(List),
    !,
    range_(From,Length,List).

range(From,Length,List) :-
    var(From),
    var(Length),
    ground(List),
    !,
    range_(From,Length,List).

range_(_,0,[]) :- !.
range_(Current,Length0,[Current|T]) :-
    !,
    Length #= Length0 - 1,
    Next #= Current + 1,
    range_(Next,Length,T).

Example run

Welcome to SWI-Prolog (threaded, 64 bits, version 8.5.5)

?- working_directory(_,'C:/Users/Groot').
true.

?- [example].
true.

?- range(From,Length,[3,4,5,6]).
From = 3,
Length = 4.

?- range(3,4,L).
L = [3, 4, 5, 6].

1 Like

I made a minor change to your program:

:- use_module(library(clpfd)).

range(_, 0, []).
range(From, Len, R) :-
  Len #> 0,
  From2 #= (From + 1),
  Len2 #= (Len - 1),
  R = [From|R2],
  range(From2, Len2, R2).

It works now.

?- range(From,Length,[3,4,5,6]).
From = 3,
Length = 4 ;
false.

?- range(3,4,L).
L = [3,4,5,6] ;
false.

?- range(3, N, Lst).
N = 0,
Lst = [] ;
N = 1,
Lst = [3] ;
N = 2,
Lst = [3,4] ;
N = 3,
Lst = [3,4,5] 

?- range(3, 4, [3,X,Y,6]).
X = 4,
Y = 5 ;
false.

?- range(F, Len, [X,Y,6,7,8]).
F = X, X = 4,
Len = Y, Y = 5 ;
false.
1 Like
range(Start, End, List) :-
    List = [Start|_],
    when(ground(List), append(_, [End], List)),
    bagof(X, between(Start, End, X), List).

:rofl:

1 Like

Waow, thank you so much everyone for being so reactive on a sunday ! it really helps a lot :slight_smile:

1 Like