Python 使用柯里化的高阶函数,尽管可以使用普通函数表现柯里化,但只有将柯里化用于高阶函数时,其价值才会真正显现。在理想情况下,functools.reduce()
函数是可柯里化的,因此可以如下操作:
sum = reduce(operator.add)
prod = reduce(operator.mul)
然而这样做并不起作用。内置的reduce()
函数不能经由PyMonad库实现柯里化,因此上面的例子实际上无法正常运作。但是,如果自定义了reduce()
函数,那么就可以如前所示对其进行柯里化了。
下面是一个自定义的reduce()
函数,可以如前所述使用它:
from collections.abc import Sequence
from pymonad import curry
@curry
def myreduce(function, iterable_or_sequence):
if isinstance(iterable_or_sequence, Sequence):
iterator= iter(iterable_or_sequence)
else:
iterator= iterable_or_sequence
s = next(iterator)
for v in iterator:
s = function(s,v)
return s
函数myreduce()
的行为和内置的reduce()
函数类似。函数myreduce()
适用于可迭代对象或者序列对象。对于给定序列,可以创建一个迭代器,而对于给定的可迭代对象,可以直接使用它。使用迭代器中的第一项来初始化结果。将该函数应用于进行中的求和(或乘积)以及随后的每一项。
还可以封装内置的
reduce()
函数来创建一个可柯里化的版本。只需两行代码便可以实现,这留给读者作为练习。
由于myreduce()
函数是一个柯里化函数,因此接下来可以基于该高阶函数创建函数。
>>> from operator import add
>>> sum = myreduce(add)
>>> sum([1,2,3])
6
>>> max = myreduce(lambda x,y: x if x > y else y)
>>> max([2,5,3])
5
我们通过应用于add
运算符的柯里化归约自定义了sum()
函数,还使用选取两个值中较大值的匿名函数对象自定义了默认的max()
函数。
由于柯里化关注位置参数,因此无法以这种方式简单地创建出max()
函数的更通用的形式。如果使用key=
关键字参数,那么为了实现函数式编程简洁明了的整体目标,会在技术上带来极大的复杂性。
为了创建一个更通用的max()
函数,需要摆脱函数max()
、min()
和sorted()
等依赖的key=
关键字参数范式。必须像filter()
、map()
和reduce()
函数那样以高阶函数作为第一个参数。还可以创建一个更统一的高阶柯里化函数库,这些函数将完全依赖位置参数。首先以高阶函数为参数,这样自定义的柯里化max(function, iterable)
方法就能遵循map()
、filter()
和functools.reduce()
等函数设置的模式了。