Skip to content

Instantly share code, notes, and snippets.

@k3ut0i
Last active December 23, 2021 18:02
Show Gist options
  • Save k3ut0i/34c647576b3bc8159a74ccff03bffe7e to your computer and use it in GitHub Desktop.
Save k3ut0i/34c647576b3bc8159a74ccff03bffe7e to your computer and use it in GitHub Desktop.
Prolog tail call optimization problem

Simple phase_step predicate.

phase_step(I, O) :- O is I + 1.
step_n(0, I, I).
step_n(N, In, Out) :-
    prolog_current_frame(Z), format('~w ', Z),
    N > 0, N1 is N -1, phase_step(In, T),
    step_n(N1, T, Out).
:- step_n(10, 1, X).
362 362 362 362 362 362 362 362 362 362

Same stack frame.

My use case, a complicated phase_step predicate.

% pattern for the nth digit mth-coeffcient
digit_m(N, M, D) :-
    divmod(M, N, Q, _),  divmod(Q, 4, _, C),
    (C = 0, D = 0; C = 1, D = 1; C = 2, D = 0; C = 3, D = -1).

calculate_digit_n(N, In, D) :-
    calculate_digit_n_(N, In, D, 1, 0).
calculate_digit_n_(_, [], D, _, Acc) :- D1 is abs(Acc), divmod(D1, 10, _, D).
calculate_digit_n_(N, [I | Is], D, M, Acc) :-
    digit_m(N, M, C), P is C*I, M1 is M+1, Acc1 is Acc+P,
    calculate_digit_n_(N, Is, D, M1, Acc1).

phase_step(In, Out) :-
    length(In, L), L1 is L + 1, phase_step_(In, Out, L1, 1, []).
phase_step_(_, Out, L, L, Acc) :- reverse(Out, Acc).
phase_step_(In, Out, L, N, Acc) :-
    N < L, calculate_digit_n(N, In, D), N1 is N + 1,
    phase_step_(In, Out, L, N1, [D | Acc]).

step_n(0, I, I).
step_n(N, In, Out) :-
    prolog_current_frame(Fr), format('~w ', Fr),
    N > 0, N1 is N - 1, phase_step(In, T),
    step_n(N1, T, Out).
:- step_n(10, [1, 2, 3, 4, 5, 6, 7, 8], X).
362 3183 6004 8825 11646 14467 17288 20109 22930 25751

Different stack frame every time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment