你需要使用一个累加器(accumulator)。虽然你可以像这样做:
list_length([] , 0 ).
list_length([_|Xs] , L ) :- list_length(Xs,N) , L is N+1 .
这将递归到列表的最后,然后当每个调用返回时,将长度加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/尾递归优化),以便在每次调用时重用堆栈帧(因为在递归调用之后没有任何局部变量被使用),从而将递归精美地转换为迭代。