Old habits never die ;-)

Crafting some nice declarative non-procedural code tonight :laughing:

?- columnSums([[1,1],[3,1]], S).
S = [4, 2].
columnSums(ListOfRows, ColumnSums):-
    Outer = ListOfRows,
    Outer = [FirstInner | _],
    length(Outer, LengthOuter),
    length(FirstInner, LengthInner),
    findall(
        X,
        (
            between(1, LengthInner, IndexInner),
            findall(
                Y,
                (
                    between(1, LengthOuter, IndexOuter),
                    nth1(IndexOuter, Outer, AnOuter),
                    nth1(IndexInner, AnOuter, Y)
                ),
                Ys
            ),
            sum_list(Ys, X)
        ),
       ColumnSums
    ).

Just in case you should need something a bit more efficient, you could try

:- use_module(library(clpfd),[transpose/2]).

columnSums(ListOfRows, ColumnSums):-
  transpose(ListOfRows,ListOfColumns),
  maplist(sum_list,ListOfColumns,ColumnSums).
2 Likes

Love the definition of clpfd:transpose/2 – a cornucopia of maplist/4 and foldl/4!

transpose(Ls, Ts) :-
    must_be(list(list), Ls),
    lists_transpose(Ls, Ts).

lists_transpose([], []).
lists_transpose([L|Ls], Ts) :-
    maplist(same_length(L), Ls),  % this is an assertion
    foldl(transpose_, L, Ts, [L|Ls], _).

transpose_(_, Fs, Lists0, Lists) :-
    maplist(list_first_rest, Lists0, Fs, Lists).

list_first_rest([L|Ls], L, Ls).
1 Like

That’s much more compact, thanks :slight_smile:

1 Like

Cool! Really elegant.

So elegant.