Python 函数式复合和PyMonad*运算符,柯里化函数的一个重要价值是可以通过函数式复合来组合函数。第5章和第11章介绍了函数式复合。
创建了一个柯里化函数后,就可以更轻松地通过函数式复合来创建新的、更复杂的柯里化函数了。例如PyMonad包定义了*
运算符来复合两个函数。为了解释这个运算符的工作原理,下面定义两个用于复合的柯里化函数。首先定义一个用于计算乘积的函数,然后定义一个用于计算特定范围值的函数。
用于计算乘积的第一个函数如下所示:
import operator
prod = myreduce(operator.mul)
该函数基于此前定义的柯里化函数myreduce()
。它使用operator.mul()
函数来计算一个可迭代对象的乘法归约,换言之,将乘积定义为了一组序列的乘法归约。
用于生成一系列数值的第二个柯里化函数如下所示:
@curry
def alt_range(n):
if n == 0:
return range(1, 2) # Only the value [1]
elif n % 2 == 0:
return range(2, n+1, 2)
else:
return range(1, n+1, 2)
函数alt_range()
的结果可以是偶数也可以是奇数。如果n
是奇数,则结果只包含到n
(含)的奇数值;如果n
是偶数,则结果只包含到n
的偶数值。这种序列对于实现半阶乘函数或双阶乘函数 n!!
尤为重要。
下面介绍如何将prod()
函数和alt_range()
函数组合成一个新的柯里化函数。
>>> semi_fact = prod * alt_range
>>> semi_fact(9)
945
这里PyMonad的*
运算符将两个函数组合成了复合函数semi_fact
。它对参数使用函数alt_range()
,随后prod()
函数会使用alt_range
函数的结果。
使用PyMonad的*
运算符等同于创建一个新的匿名函数对象。
semi_fact = lambda x: prod(alt_range(x))`
与创建一个新的匿名函数对象相比,柯里化函数的复合涉及的语法要少一些。
理想情况下,我们希望能如下所示使用函数式复合和柯里化函数:
sumwhile = sum * takewhile(lambda x: x > 1E-7)
这样就可以定义一个适用于无穷序列的sum()
函数版本,并且在满足阈值条件时停止生成新的值。然而由于PyMonad库处理无穷迭代对象的能力似乎不及处理内部List
对象的能力,因此这种做法实际上不起作用。