アキュムレータを使用する必要があります。あなたはこのようなことをすることができますが:
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 である新しいアキュムレータを作成します。リストの最後に到達すると、アキュムレータの値は望ましい結果。
プロローグ エンジンは十分にスマート (TRO/末尾再帰の最適化) であるため、各呼び出しでスタック フレームを再利用できることがわかります (再帰呼び出しの後にローカルは使用されないため)。したがって、再帰を反復にきちんと変換します。