@gusbroが言ったこと。さらに、異なる長さのリストに対処するために、操作の順序を再編成し、いくつかの特別なケースを追加する必要があります。
list_sum( [] , [] , [] ) .
list_sum( [] , [Y|Ys] , [Z|Zs] ) :- Z is 0+Y , list_sum( [] , Ys , Zs ) .
list_sum( [X|Xs] , [] , [Z|Zs] ) :- Z is X+0 , list_sum( Xs , [] , Zs ) .
list_sum( [X|Xs] , [Y|Ys] , [Z|Zs] ) :- Z is X+Y , list_sum( Xs , Ys , Zs ) .
Z is X+Y
上記の例では評価 ( ) を移動する必要があるため、再帰の前Z
に評価されます。これにより、次の 2 つのことが達成されます。
まず、述語をtail-recursiveにします。これは、ソリューションが反復的であるため、スタック スペースを消費しないことを意味します。コードでは、再帰全体が完了するまで評価は実行されません。各中間合計はスタックに保持され、戻る途中で右から左に評価されます。これは、大きなリストでスタックを吹き飛ばすことを意味します。
第二に、再帰する前に各結果を評価するということは、すぐに失敗することを意味します。結果と一致しない最初の合計は、操作全体に失敗します。あなたのソリューションはゆっくりと失敗します。最初の項目の合計が結果リストの最初の項目にならない 10,000,000 個の項目リストを考えてみましょう: 10,000,000 個の項目すべてをトラバースし、 — スタックを吹き飛ばさなかったと仮定して — 合計を右から左に評価し始めます。あなたの述語は、最後の評価まで失敗しません。