是的,你的解決方案是最優的,因爲它會爲樹中的每個節點調用sum/2謂詞一次(並且你無法減少調用)。不,您可以通過使用累加器自己實現堆棧來實現尾遞歸。
下面是一個示例(未測試)。扁平化謂詞可以與sum相結合,但爲了清晰起見,它們是不同的(均爲尾遞歸):
flatten([], Acc, Acc).
flatten([void|ToGo], Acc, Result) :-
flatten(ToGo, Acc, Result).
flatten([t(V,L,R)|ToGo], Acc, Result) :-
flatten([L,R|ToGo], [t(V,L,R)|Acc], Result).
flatten(Root, Result) :-
flatten([Root], [], Result).
sum([], Result, Result).
sum([t(V,_,_)|ToGo], Acc, Result) :-
NewAcc is Acc+V,
sum(ToGo, NewAcc, Result).
sum(Tree, Result) :-
flatten(Tree, FlatTree),
sum(FlatTree, 0, Result).