受講しているクラスの講義ノートの一部を理解しようとしています。長さ関数を次のように定義します。
length = foldr (\_ n -> 1 + n) 0
誰かがこれがどのように機能するか説明できますか? 私はそれについて私の心を包むことができません。
受講しているクラスの講義ノートの一部を理解しようとしています。長さ関数を次のように定義します。
length = foldr (\_ n -> 1 + n) 0
誰かがこれがどのように機能するか説明できますか? 私はそれについて私の心を包むことができません。
まず、タイプfoldr
:(a -> b -> b) -> b -> [a] -> b
使用法をコンテキストにfoldr
取り入れて、3つの引数を取ります:関数(a。リストの要素とb。アキュムレータを取り込んで、アキュムレータを返します)、アキュムレータの開始値、およびリスト。foldr
リストを介して関数を適用した後、アキュムレータの最終結果を返します。
このコードについて:
length = foldr (\_ n -> 1 + n) 0
ご覧のとおり、リストがありません。したがって、右側の戻り値は、リストを取り込んでInt(と同じ型0
)を生成する関数です。タイプ:[a] -> Int
。
右側の意味については:(\_ n -> 1 + n) 0
\
名前のない関数を宣言することを意味します
_
リストから要素を無視することを意味します(a
のタイプに対応しfoldr
ます)。ご存知のfoldr
ように、リストを調べて、各要素に関数を適用します。これは、関数に渡される要素です。関数では使用しないlength
ので、無視する必要があることを示します。
n
アキュムレータとして渡されるIntのパラメータです。
->
戻ることを意味します
1 + n
アキュムレータをインクリメントします。戻り値がに戻され、関数への次の呼び出しに渡すために値が保存されることを想像foldr
できfoldr
ます(\_ n -> 1 + n)
。
括弧の0
外側は、カウンターの開始値です。
関数foldr
は右結合演算子でリストを折り畳むことです。演算子(+)
, を使用すると、関数が何をするかを簡単に理解できます (関数は と同じ動作をしますsum
):
foldr (+) 0 [1,2,3,4,5] = 1+(2+(3+(4+(5+0))))
長さ関数の場合、次と同等です。
foldr (\_ n -> 1 + n) 0 [1,2,3,4,5] = 1+(1+(1+(1+(1+0))))
それがfoldr
目的です
それを理解するには、いくつかの同等の方法があります。1 つ目:foldr f z [1, 2, 3, 4, ..., n]
次の値を計算します。
f 1 (f 2 (f 3 (f 4 (f ... (f n z)))))
だからあなたの場合:
length [1,2,3,4] = foldr (\_ n -> 1 + n) 0 [1,2,3,4]
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 ((\_ n -> 1 + n) 3 ((\_ n -> 1 + n) 4 0)))
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 ((\_ n -> 1 + n) 3 (1 + 0)))
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 (1 + (1 + 0)))
= (\_ n -> 1 + n) 1 (1 + (1 + (1 + 0)))
= 1 + (1 + (1 + (1 + 0)))
= 1 + (1 + (1 + 1))
= 1 + (1 + 2)
= 1 + 3
= 4
もう 1 つは、リストをコピーするこの関数から開始することです。
listCopy :: [a] -> [a]
listCopy [] = []
listCopy (x:xs) = x : listCopy xs
些細な関数のように見えるかもしれませんが、基本的にはそれだけですが、空のリストとペア コンストラクターを右側foldr
にハードコーディングすることを除いて、引数として提供される任意の定数と関数を使用します。私はときどきこれらの引数を and ( andは Lisp 言語の演算子と定数の名前です) と呼ぶのが好きです。ある意味では、リストを「コピー」しているのに偽のコンストラクタを使用しているためです。[]
:
fakeCons
fakeNil
cons
nil
:
[]
foldr fakeCons fakeNil [] = fakeNil
foldr fakeCons fakeNil (x:xs) = fakeCons x (subfold xs)
where subfold = foldr fakeCons fakeNil
したがって、この解釈では、length
関数はリストを「コピー」していますが、空のリストの代わりに を使用し、要素を破棄して現在の合計に 1 を追加する0
代わりに.:
の 3 番目の解釈は次のfoldr f z xs
とおりです。
z
リストが空の場合の問題の解決策です。f
list の要素と部分的な解決策の 2 つの引数を取る関数です:に渡された要素の右側に表示される要素のリストに対する問題の解決策f
です。 f
次に、「1要素大きい」ソリューションを生成します。したがって、次の場合length
:
foldr
。xs
さn
はx:xs
ですn+1
。foldr
それが、 ,への最初の引数\_ n -> n + 1
が行っていることです: リストの長さを計算し、引数としてリストの最初の要素 (この場合は無視します) とリストの残りの長さ ( n
) を指定します。この考え方foldr
は非常に強力であり、過小評価すべきではありません。基本的に、最初の引数として に渡す関数では、foldr
解決しようとしている問題が、扱っているリストよりも短いすべてのリストについて既に解決されていると想定することができます。したがって、引数関数がしなければならないことは、1 要素長いリストの答えを計算することだけです。