Reputation: 57
so I'm quite new to prolog and I have to add up all the elements of a list.
listSum([],0).
listSum([Head|Tail], Sum) :- listSum(Tail,TailSum), Sum is Head + TailSum.
The goal is to make this tail-recursive and I was wondering if that was a better way to do it than this
listSum([],0).
listSum(List, Sum) :- listSum(List,Sum,0).
listSum([H|T], Sum, S) :- S1 is S+H, listSum(T, Sum, S1).
listSum([], Sum, S) :- Sum is S.
Or is that perfectly fine to do? Just looking to see if there's any obvious way to improve the above code that I'm missing out on.
Thanks.
Upvotes: 1
Views: 840
Reputation:
This looks perfectly fine to me. You can save yourself some writing by not doing the unnecessary stuff. First, you get 0 from two separate places; it would be enough to get it from one. Also, "output" arguments are supposed to come after all other arguments.
list_sum(L, S) :-
list_sum(L, 0, S).
Then, you don't need the is/2
in the base case:
list_sum([], S, S).
list_sum([X|Xs], S0, S) :-
S1 is S0 + X,
list_sum(Xs, S1, S).
Of course, you could decide to actually save one step in the tail-recursive definition:
list_sum([], 0).
list_sum([X|Xs], S) :-
list_sum(Xs, X, S).
list_sum([], S0, S) :- S is S0.
list_sum([X|Xs], S0, S) :-
S1 is S0 + X,
list_sum(Xs, S1, S).
You should recognize that the second version is a fold:
list_sum([], 0).
list_sum([X|Xs], S) :-
foldl(add, Xs, X, S).
add(X, Y, S) :- S is X+Y.
Or, even directly:
list_sum(List, Sum) :- foldl(add, List, 0, Sum).
Upvotes: 2