是的,您的解决方案是最优的,因为它会为树中的每个节点只调用一次 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).