% Write a predicate to colpute the sum of two numbers written as a list, without transforming the list in a number.
% Eg: [1 1 1][2 3 4] -> [3 4 5]

% my_append(L:list, E:element, R:list)
% flow model: (i i o)
% my_append(l1l2...ln, e) =
%   e, n = 0
%   l1 + my_append(l2l3...ln, e), otherwise
my_append([], L, L).
my_append([H|T], L, [H|Result]) :-
    my_append(T, L, Result).

% reverse_order(L:list, R:list)
% flow model: (i o)
% reverse_order(l1l2...ln) =
%   [], n = 0
%   reverse_order(l2l3...ln) + l1, otherwise
reverse_order([], []).
reverse_order([H|T], R) :-
    reverse_order(T, R1),
    my_append(R1, [H], R).

% sum(L1:list, L2:list, C:integer, R:list)
% flow model: (i i i o)
% sum(l1l2...ln, l1l2...lm, c) =
%   [], n = 0 and m = 0 and c = 0
%   [1], n = 0 and m = 0 and c = 1
%   l1l2...ln, n != 0 and m = 0 and c = 0
%   l1l2...ln + 1, n != 0 and m = 0 and c = 1
%   l1l2...lm, n = 0 and m != 0 and c = 0
%   l1l2...lm + 1, n = 0 and m != 0 and c = 1
%   l1 + l2 + c + sum(l2l3...ln, l2l3...lm, 0), otherwise
 
sum([], [], 0, []).
sum([], [], 1, [1]).
sum([H1|T1], [], 0, [H1|T1]).
sum([], [H2|T2], 0, [H2|T2]).
sum([H1|T1],[],1,R) :-
    H3 is H1 + 1,
    H3 < 10,
    R = [H3|T1].
sum([H1|T1],[],1,R) :-
    H3 is H1 + 1,
    H3 >= 10,
    H4 is H3 - 10,
    sum(T1, [], 1, T3),
    R = [H4|T3].
sum([],[H2|T2],1,R) :- 
    H3 is H2 + 1,
    H3 < 10,
    R = [H3|T2].
sum([],[H2|T2],1,R) :-
    H3 is H2 + 1,
    H3 >= 10,
    H4 is H3 - 10,
    sum([], T2, 1, T3),
    R = [H4|T3].
sum([H1|T1], [H2|T2], C, [H3|R]) :-
    S is H1 + H2 + C,
    S < 10,
    H3 is S,
    sum(T1, T2, 0, R).
sum([H1|T1], [H2|T2], C, [H3|R]) :-
    S is H1 + H2 + C,
    S >= 10,
    H3 is S - 10,
    sum(T1, T2, 1, R).


% sum_lists(L1:list, L2:list, R:list)
% flow model: (i i o)
% sum_lists(l1l2...ln, l1l2...lm) =
%   reverse_order(sum(reverse_order(l1l2...ln), reverse_order(l1l2...lm)))

sum_lists(L1, L2, R) :-
    reverse_order(L1, R1),
    reverse_order(L2, R2),
    sum(R1, R2, 0, R3),
    reverse_order(R3, R).

