您需要使用累加器。虽然你可以做这样的事情:
list_length([] , 0 ).
list_length([_|Xs] , L ) :- list_length(Xs,N) , L is N+1 .
它将一直递归到列表的末尾,然后在每次调用返回时,将长度加一,直到返回到具有正确结果的顶层。
这种方法的问题是每次递归都会在堆栈上推送一个新的堆栈帧。这意味着如果列表足够长,您将 [最终] 用完堆栈空间。
相反,使用尾递归中介,如下所示:
list_length(Xs,L) :- list_length(Xs,0,L) .
list_length( [] , L , L ) .
list_length( [_|Xs] , T , L ) :-
T1 is T+1 ,
list_length(Xs,T1,L)
.
此代码为一个带有累加器的工作谓词提供种子,种子为 0。在每次递归时,它都会创建一个新的累加器,其值为当前值 + 1。到达列表末尾时,累加器的值与期望的结果。
prolog 引擎足够聪明(TRO/Tail Recursion Optimization),可以看到它可以在每次调用时重用堆栈帧(因为在递归调用之后没有使用任何局部变量),从而巧妙地将递归转换为迭代。