はじめに
Pythonで合成関数っぽいものを作るときの、いわゆるPythonらしいコードの書き方です。どんな気持ちでコードを綴っているかを付記しておきます。
なにがしたいのか
たとえば
f: A \to B\\
g: B \to C
みたいな関数が2つあって、
h = g\circ f:A \to C
を作りたい。
実装例
2つ実装を載せておきます。
再帰を使う
実際に前から一つずつ適用していく方法で、一番直感的にスッキリと書けます。
def composite(*funcs):
f, *rest = funcs
return lambda *x: composite(*rest)(f(*x)) if rest else f(*x)
composite(
lambda x, y: x * y,
lambda x: 2 * x,
lambda x: x + 3
)(5, 7) # (2 * (5 * 7)) + 3 = 73
関数列(*funcs
)をうけとって、
- head(
f
)とtail(*rest
)に分解し - headを適用した値(
f(*x)
)を、tailの合成関数(再帰)に適用する - tailに中身がなきゃheadを適用する
- ような関数を返す
というようなイメージでコードを書いています。
再帰側から先に書いて、終わる条件をあとから付け足すようなイメージで書くと書きやすい構文になっています。
reduce
を使う
関数列を畳み込む方法で、使い捨てで書きやすいです。
from functools import reduce
reduce(
lambda f, g: lambda *x: g(f(*x)),
[
lambda x, y: x * y,
lambda x: 2 * x,
lambda x: x + 3,
]
)(5, 7) # (2 * (5 * 7)) + 3 = 73
畳み込みの関数さえかければ、あとは関数列を並べるだけですね。左から畳み込みます。
- 関数を2つうけとって
- まるっと適用してくれる関数を返す
さいごに
Pythonはかゆいところに手が届く構文、組み込みがあってよい。