Here's a logically clean implementation of the zs_from_to/3 predicate using clpfd :
:- use_module(library(clpfd)). zs_from_to([],I0,I) :- I0
Let me use it! First, some ground queries:
? - zs_from_to ([1,2,3], 1,3).
true
? - zs_from_to ([1,2, 3 ], 1, 4 ).
false
Next, a few more general queries:
?- zs_from_to(Zs,1,7). Zs = [1,2,3,4,5,6,7] ; false. ?- zs_from_to([1,2,3],From,To). From = 1, To = 3.
Now let's look at even more general queries:
?- zs_from_to(Zs,From,2). Zs = [], From in 3..sup ; Zs = [2], From = 2 ; Zs = [1,2], From = 1 ; Zs = [0,1,2], From = 0 ; Zs = [-1,0,1,2], From = -1 ; Zs = [-2,-1,0,1,2], From = -2 ... ?- zs_from_to(Zs,0,To). Zs = [], To in inf.. -1 ; Zs = [0], To = 0 ; Zs = [0,1], To = 1 ; Zs = [0,1,2], To = 2 ; Zs = [0,1,2,3], To = 3 ; Zs = [0,1,2,3,4], To = 4 ...
What answers do we get for the most general request?
?- zs_from_to(Xs,I,J). Xs = [], J#=<I+ -1 ; Xs = [I], I+1#=_A, J#>=I, J#=<_A+ -1 ; Xs = [I,_A], I+1#=_A, J#>=I, _A+1#=_B, J#>=_A, J#=<_B+ -1 ; Xs = [I,_A,_B], I+1#=_A, J#>=I, _A+1#=_B, J#>=_A, _B+1#=_C, J#>=_B, J#=<_C+ -1 ...
Edit 2015-06-07
To improve the implementation of zs_from_to/3 above, do two things:
- Try to improve implementation determinism.
- Extract a more general higher order idiom and implement
zs_from_to/3 on top of it.
Introducing the meta predicates init0/3 and init1/3 :
:- meta_predicate init0(2,?,?). :- meta_predicate init1(2,?,?). init0(P_2,Expr,Xs) :- N is Expr, length(Xs,N), init_aux(Xs,P_2,0). init1(P_2,Expr,Xs) :- N is Expr, length(Xs,N), init_aux(Xs,P_2,1). :- meta_predicate init_aux(?,2,+). % internal auxiliary predicate init_aux([] , _ ,_ ). init_aux([Z|Zs],P_2,I0) :- call(P_2,I0,Z), I1 is I0+1, init_aux(Zs,P_2,I1).
See init0/3 and init1/3 in action!
? - init 0 ( = , 5, Zs). %? - numlist ( 0 , 4, Xs), maplist (=, Xs, Zs).
Zs = [0,1,2,3,4].
? - init 1 ( = , 5, Zs). %? - numlist ( 1 , 5, Xs), maplist (=, Xs, Zs).
Zs = [1,2,3,4,5].
Ok, where are we going? Consider the following query:
? - init0 ( plus (10) , 5, Zs). %? - numlist (0,4, Xs), maplist ( plus (10) , Xs, Zs).
Zs = [10,11,12,13,14].
Almost done! Combining it, we define zs_from_to/2 as follows:
z_z_sum(A,B,C) :- C
Finally, see if determinism has improved!
?- zs_from_to(Zs,1,7). Zs = [1,2,3,4,5,6,7]. % succeeds deterministically