カリー化した関数に型ヒントを与える

Pythonの型ヒントに慣れるために、カリー化した関数に型ヒントを与えるというタスクをやってみる。

ちなみに、カリー化とは、複数の引数をとる関数を、一つの引数だけをとる関数のチェーンに変換する操作のことである。

以下、簡単なカリー化の例(Python)。

# 引数2つの場合
add_2num = lambda x, y: x + y 
cadd_2num = lambda x: lambda y: x + y # カリー化後

# 引数3つの場合
add_3num = lambda x, y, z: x + y + z
cadd_3num = lambda x: lambda y: lambda z: x + y + z # カリー化後

カリー化した関数は、下記のように使用できる。

add_2num(1,2) # 3
cadd_2num(1)(2) # 3

add_3num(1,2,3) # 6
cadd_3num(1)(2)(3) # 6

increment = cadd_2num(1) # 部分適用
increment(2) # 3

さらに進んで、カリー化した関数に型ヒントを与えてみる。

from typing import Callable

# 引数2つの場合
add_2num: Callable[[float, float], float] = lambda x, y: x + y
cadd_2num: Callable[[float], Callable[[float], float]] = lambda x: lambda y: x + y

# 引数3つの場合
add_3num: Callable[[float, float, float], float] = lambda x, y, z: x + y + z
cadd_3num: Callable[[float], Callable[[float], Callable[[float], float]]] = lambda x: lambda y: lambda z: x + y + z

cadd_2num(1)(2) # 3
cadd_2num(1)('2') # TypeError: intとstringを+演算しようとしてエラー
cadd_2num('1')('2') # 12 エラーは発生しない

mypyで型チェックをしてみる。

mypy main.py

# curried.py:12: error: Argument 1 has incompatible type "str"; expected "float"
# curried.py:13: error: Argument 1 has incompatible type "str"; expected "float"

cadd_2num('1')('2')の2番目の引数の不正は指摘してくれないのは、何故なのか...

参考

https://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%AA%E3%83%BC%E5%8C%96 https://www.ibm.com/developerworks/jp/java/library/j-jn9/index.html