HaskellとMathematicaの畳み込み関数
Haskellには、左結合の畳み込み関数 foldl, foldl1 と右結合の畳み込み関数 foldr, foldr1 が定義されている。
foldl は引数に2変数関数、初期値、リストを順に取り、リストを頭から順に続けて演算した最終的な結果を返す。たとえば、この場合
foldl (+) 0 [1,2,3,4,5] -- = 15
は、(((((0+1)+2)+3)+4)+5) を計算する。
foldl の初期値の無いバージョンが foldl1 である。同様な例として
foldl1 (+) [1,2,3,4,5] -- = 15
は、((((1+2)+3)+4)+5) を計算する。
Haskell における上記の2関数と同等なものが、Mathematica では Fold 関数で定義されている。
Fold[f, x, list] とした場合には foldl に相当し、Fold[f, list] とした場合には foldl1 に相当する。上記に挙げたのと同じ例を見てみると
Fold[Plus, 0, {1,2,3,4,5}] (* = 15 *)
Fold[Plus, {1,2,3,4,5}] (* = 15 *)
となる。
Haskell の話に戻るが、リストを頭から順に続けて演算したときの途中途中の結果をリストにして返す関数があり、scanl, scanl1 という名前で使える。
scanl は foldl と全く同様な引数を取り、
scanl (+) 0 [1,2,3,4,5] -- = [0,1,3,6,10,15]
のように配列が返される。返った配列の最後の要素の値が、foldl に同じ引数を適用したときの結果と一致していることが分かる。数式的に書けば
[0, 0+1, (0+1)+2, ((0+1)+2)+3..., (((((0+1)+2)+3)+4)+5)]
というようなリストを生成している。
fold の場合と同じく scanl の初期値が無いバージョンが scanl1 である。
scanl1 (+) [1,2,3,4,5] -- = [1,3,6,10,15]
また、scanr, scanr1 も定義されていて、名前から分かるようにこれらは 右結合のバージョンである。
では scan 系関数が Mathematica では何に当たるかというと、それは実は FoldList である。結局 Fold をするけど List で返すよ、という分かり易い名前である(と思う)。使い方も Fold と同じシンタックスを取れるので
FoldList[Plus, 0, {1,2,3,4,5}] (* = {0,1,3,6,10,15} *)
FoldList[Plus, {1,2,3,4,5}] (* = {1,3,6,10,15} *)
というふうになる。
以上に見てきたように、Haskell では関数の型に縛られて、同様の機能を持つ関数が foldl, foldl1 のように名前が異なる亜種として定義されているが、Mathematica はそのような縛りがなく、引数も可変長であるので1つの関数で複数の使い方ができる。なお、Haskell では左結合・右結合ともに用意されているが、Mathematica では左結合の関数だけで、右結合版は見当たらないようだ…。
ちなみに、Mathematica の FoldList の初期値の無い例については、Accumulate[list] という似たような関数が定義されている。