В качестве примечания, вычисление суммы, предложенное @aioobe, не является оптимальным, потому что в очень большом списке вам не хватит памяти стека вызовов.
Особая техника - поместить рекурсивный вызов предиката в качестве последнего элемента вашего предиката. Таким образом, когда все предыдущие вещи уже вычислены, Prolog может сбросить текущий контекст предиката при выполнении рекурсивного вызова. В списке с элементами 1M это означает, что вы будете работать с сохранением 1 контекста вместо одного миллиона.
Хотя это может показаться вам неважным для этого конкретного упражнения, оптимизация хвостового вызова - это то, что делает рекурсию такой же мощной, как итерация, если принять во внимание потребление пространства. Это стоит учиться!
Вот версия, на которой Оптимизация Tail Call может выполняться:
sumlist(List, Result) :-
sumlist(List, 0, Result).
sumlist([], Acc, Acc).
sumlist([Item|List], Acc, Result) :-
NewAcc is Acc + Item.
sumlist(List, NewAcc, Result).
В нем используется идиома, которую вы часто встречаете в декларативном программировании: аккумулятор (здесь он называется Acc
). Его цель - сохранить полученное значение «до сих пор» во время рекурсии.