Generate list - geometric progression

2019-05-16 11:19发布

问题:

I'd like to generate a geometric progression list using a predicate with 4 parameters - the list where the progression will be generated, the length of this list, the start element, and the multiplier of the progression. What I've done so far is having only a 3-parameter predicate to generate the geometric progression without stopping :

gengeom([X],X,_).
gengeom([H|Tail],H,Q):-X is H*Q,gengeom(Tail,X,Q).

And this query gives me all progressions with start element 1 and multiplier 2 :

?-gengeom(L,1,2),write(L),nl,fail.

Can anyone help me write the 4-parameter predicate I'd really like to have (that stops generating any more numbers after the length of the list has become a certain number) ?

回答1:

just adding a countdown parameter will work, and will preserve the nice generative property of your code:

gengeom([X],X,_,_).
gengeom([H|Tail],H,Q,N) :- N>1, M is N-1, X is H*Q, gengeom(Tail,X,Q,M).

?- gengeom(L,1,2,3).
L = [1] ;
L = [1, 2] ;
L = [1, 2, 4] ;
false.

of course, you could get somewhat more compact using findall/3, the Prolog 'list generator':

gengeom(L,H,Q,N) :-
    findall(V, (between(H,N,M), V is Q**(M-1)), L).

but this snippet (similar to @joel76' post) will build just the 'final' list...



回答2:

With SWI-Prolog, you can write :

:- use_module(library(lambda)).

gengeom(Len, Start, Multiplier, L) :-
    length(L, Len),
    foldl(\X^Y^Z^(X = Y,
                 Z is Y * Multiplier),
          L, Start, _).

For example :

?- gengeom(5, 1, 2, L).
L = [1, 2, 4, 8, 16].


回答3:

Well, as you asked, including the length parameter you need update your stop condition to be true when the length of the list is one, and the general clause, must decrement this length on each step.
Now gengeom/4 predicate will look like this:

gengeom([X], X ,_, 1):- !.
gengeom([H|Tail], H, Q, N):-N > 0, X is H * Q, N1 is N - 1, gengeom(Tail, X, Q, N1).

This find the progression with start 1, multiplier 2 and length 5

?- gengeom(L, 1, 2, 5).
L = [1, 2, 4, 8, 16]

You can find all solutions from length 1 to the selected length, using the metapredicate findall/3:

findall(L, (member(N, [1,2,3,4,5]), gengeom(L,1,2, N)), R).

This should be complete:

gengeom([X], X ,_, 1):- !.
gengeom([H|Tail], H, Q, N):-N > 0, X is H * Q, N1 is N - 1, gengeom(Tail, X, Q, N1).

generate(Start, Step, Stop):- findall(L, (numlist(1,Stop, Len), member(N, Len), gengeom(L,Start,Step, N)), R), writeGen(R).

writeGen([]).
writeGen([H|Tail]):- write(H), nl, writeGen(Tail).

Test

?- generate(1, 2, 5).
[1]
[1, 2]
[1, 2, 4]
[1, 2, 4, 8]
[1, 2, 4, 8, 16]
true


标签: list prolog