Generate list - geometric progression

2019-05-16 11:13发布

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) ?

标签: list prolog
3条回答
Fickle 薄情
2楼-- · 2019-05-16 11:43

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...

查看更多
做自己的国王
3楼-- · 2019-05-16 11:51

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].
查看更多
ら.Afraid
4楼-- · 2019-05-16 12:02

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
查看更多
登录 后发表回答