(2017.8.6)
Pythonでは, 関数に ()
を付けなければ, 呼び出しではなく, 関数オブジェクトになる。別の関数呼び出しの引数として関数を渡すのがたやすい。関数を引数として取る関数を「高階関数」higher-order function という。
高階関数を使うと、アルゴリズムと適用する処理を分離することができる。ソースコードの再利用性が高まる。
高階関数と一口に言っても, いくらでもある。まずは簡単に, 内包表記の機能を支える関数を紹介する。
Python は, リストを取りそうなところには iterable を与えるようになっている。リスト内包表記も、本当にリストが欲しい場合以外は、ジェネレイタ内包表記が推奨される。
何でも iterable とイテレイタ。
ただ、概念として iterable よりもリストで考えたほうがイメージしやすいことが多い。
各要素に対して関数を適用する。
Pythonなので, リストを取って関数を適用、ではない。iterable を取って, 各要素に対して関数を適用する。
リストを取って、関数を適用し、リストを得る、と考えたほうが分かりやすい。
map()関数は、ジェネレイタの内包表記を使って, 次とまったく同じです。
要素を取捨選択する。
こちらも実際にはリストを取るわけではない。iterable の各要素に対して関数を適用して、真となった要素のみを残すようなイテレイタを返す。
filter()関数の戻り値は class 'filter' 型のオブジェクト。mapオブジェクトと同様に, iterator として振る舞う。
filter関数は次とまったく同じです
組み合わせ.
複数のイテレイタを取り、すべての組み合わせをタプルにして生成。
次と同じ。
「畳み込み」というのは, リストの隣同士の要素に対して演算を行い、結果として一つの値を得るようなもの。
演算の順序として, foldl (fold-left) と foldr (fold-right) がある。
Haskell には両方ある。foldr, foldl の宣言は次のようになっている。引数は次の3つ --関数、初期値、リスト.
それぞれ, 次のような演算が行なわれる。
foldlは次のようになる;
Haskellは遅延評価で、無限リストは いっぽう Python は正格評価で, iterableは左からしか要素が取り出せない。畳み込みは Python3で、functools モジュールに移動した。
初期値が省略された場合, リストの最初の要素が取り出され, 初期値となる。初期値が省略され、さらにリストが空だったときは、TypeErrorが投げられる。
初期値があるがリストが空、あるいは初期値が省略されてリストの要素がただ一つのときは、その値が 例;
第一引数として2つ引数を取る 最初 _内包表記を分解
map()関数
map( 関数, iterable )
map()
関数の戻り値は class 'map' 型のオブジェクト. __iter__()
, __next__()
を持ち, イテレイタとして振る舞う。
[1, 3, 5, 7, 9]
[-2, 6, -10, 14, -18]
[1, -3, 5, -7, 9]
map()
関数は、要素の数は変えず、一つ一つの要素を変換する。map() の第1引数 関数 が値を返さなかった場合, その要素は None
になる。要素が詰められるわけではない。
filter()関数
filter( 関数, iterable )
[3, 7]
product()関数
[(-1, 2), (-1, 3), (3, 2), (3, 3), (-5, 2), (-5, 3), (7, 2), (7, 3)]
_畳み込み関数
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
foldr func z [] = z
foldr func 初期値 [x0, x1, ..., xn] = x0 `func` (x1 `func` (...(xn `func` 初期値)))
foldl func z [] = z
foldl func 初期値 [x0, x1, ..., xn] = (((初期値 `func` x0) `func` x1)...) `func` xn
foldr
で扱える。foldl
とfoldr
については、例えばこの記事が興味深い; foldlを直す - 純粋関数空間
reduce()
関数という名前で, fold-left になっている。
functools.reduce( func, iterable [, 初期値] )
reduce()
の計算結果となる。
5
(+)
を与えた。この例では ((((1 + (-3)) + 5) + (-7)) + 9) => 5 となる。reduce()
の戻り値はイテレイタではなく、計算結果。
reduce()
さえあれば、ほかの畳み込む関数を作れる。ただし、組み込み関数は最適化されているはずで、無闇に自作関数を使うべきではない。
all()
, any()
は, 高階関数として作ると, 次のようになる。
True
0
c
False
a
0
a and b
, a or b
で作っていたが、隣同士で演算することもなかった。それから、この例では、条件によっては途中で脱出できる。
返す値はリストでもいい
reduce()
は、別に畳み込まなくてもいい。reduce()
に渡す第1引数がリストを返すようにすれば、reduce()
の結果もリストになる。
[]
[1, 4, 9]