したがって、投稿したコードの場合:
- 空のリストのケースは必要ありません。foldl がそれを処理します。x の代わりに xs を foldl に渡すだけです。
- foldl はカリー化されているため、パラメーターを括弧で囲むべきではありません。
それ以外は、実際には正しいように見えます。とにかく、foldl がどのように機能するのかまだよくわからない場合は、ここに非常に長く完全な説明があります ;)
さて、List.foldl から始めましょう。
val foldl : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
したがって、3 つのパラメータがあります。1 つは後で考える関数で、2 番目は戻り値の型と同じ型の値で、最後はリストです。
それでは、簡単な例を見てみましょう。たとえば、int のリストがあり、すべての数値を合計したいとします。これを行うことができます:
fun sum [] = 0
| sum (x::xs) = x + sum xs
または、foldl を使用することもできます (私は怠け者なので、List.foldl の代わりに foldl と書きます)。
したがって、リストが 3 番目のパラメーターであることがわかります。2 番目は、リストが空の場合に意味のある開始値またはアキュムレータのようなものである必要があります。合計の場合、それは 0 になります。
最初のパラメーターは関数で、ここが難しい部分です。タイプは次のとおりです。
fn : 'a * 'b -> 'b
'a はリスト内の要素の型でもあるので、これがリストの項目である場合は意味があります。'b は開始値と戻り値の型です。
実際には、foldl はリストの最初の要素とアキュムレータを使用して関数を呼び出します。次に、新しいアキュムレータとしての結果とリストの残りを使用して自分自身を呼び出します。したがって、これを行うと:
foldl foo 0 [1,2,3]
やります
foo (1,0)
その後
foldl foo (foo (1,0)) [2,3]
等々。
したがって、リストを合計するために、次の関数を作成します。
fn (x,acc) => x + acc
したがって、これを行うことができます:
fun sum xs = foldl (fn (x,acc) => x + acc) 0 xs
または、さらに単純な
val sum = foldl op+ 0
(op+
前に使用した無名関数と同じことを行います)
リストを見てみましょう[1,2,3]
foldl op+ 0 [1,2,3]
foldl op+ (op+ (1,0)) [2,3] -> foldl op+ 1 [2,3]
foldl op+ (op+ (2,1)) [3] -> foldl op+ 3 [3]
foldl op+ (op+ (3,3)) [] -> foldl op+ 6 []
6