我什么时候应该使用函数柯里化?

21 投票
3 回答
37429 浏览
提问于 2025-04-18 14:14

我什么时候应该使用柯里化函数? 这和我之前的想法不太一致,我需要纠正一下自己。

作为我学习的一部分,这个链接让我对函数柯里化有了一些理解。下面是一个例子:

def curry2(f):
    """Returns a function g such that g(x)(y) == f(x, y)

    >>> from operator import add
    >>> add_three = curry2(add)(3)
    >>> add_three(4)
    """
    def g(x):
        def h(y):
            return f(x, y)
        return h
    return g

在任何应用程序中,如果我知道参数的数量是固定的(比如说2个参数),而函数的名字是 normalise_range(假设),那么我会定义一个函数 def normalise_range(x, y):,并直接通过调用 normalise_range(x, y) 在我的应用中使用它。

在任何应用程序中,如果我知道参数的数量是固定的(比如说2个参数),但函数的名字是变化的(可能是 normalise_rangeaverage,或者我不知道..),那么我会使用 def curry2(f):,就像上面那样,这个函数可以接受所有需要两个参数的函数(固定的)。

我的问题是:

  1. 我的理解正确吗?
  2. 如果正确的话,我们能不能考虑对参数数量可变的函数进行柯里化?

3 个回答

0

从很多方面来看,把柯里化和部分参数应用结合起来,类似于我们在面向对象编程中所说的“工厂模式”。柯里化让程序员可以创建一些专门化的函数,正如其他人在这个论坛中提到的那样。比如,看看下面这个快速排序的实现,它虽然不够高效,但很优雅:

leq = lambda x: lambda y: x <= y
gth = lambda x: lambda y: x > y

def qsort(L):
    if L:
        smalls = filter(gth(L[0]), L[1:])
        bigs = filter(leq(L[0]), L[1:])
        return qsort(smalls) + [L[0]] + qsort(bigs)
    else:
        return L

print(qsort([2, 4, 1, 4, 2]))
5

柯里化有至少两个我能想到的好处:

1) 它可以让你的代码保持简洁,也能让你的思维更清晰,避免重复。

比如说,你有一个这样的函数:

def call_me(context, args):
    ...

通过柯里化,你可以得到一个针对特定上下文的专用函数,这样你就可以随意使用它,而不需要再重复写这个上下文。

2) 用一个输入的函数来思考,比起处理多个参数要简单得多;不过这有时候也可以争论。

另请参见:柯里化和部分应用有什么区别?

32

函数柯里化的目的是为了从更通用的函数中轻松得到专门化的函数。 你可以通过在不同的时间预先设置一些参数,并在之后保持这些参数不变来实现这一点。

这和命名没有关系。在Python中,你可以随时轻松地重命名变量或函数。

举个例子:

def simple_function(a):
    def line(b=0):
        def compute(x):
            return [a+b * xi for xi in x]
        return compute
    return line

x = range(-4, 4, 1)
print('x {}'.format(list(x)))
print('constant {}'.format(simple_function(3)()(x)))
print('line {}'.format(simple_function(3)(-2)(x)))

结果是

x [-4, -3, -2, -1, 0, 1, 2, 3]
constant [3, 3, 3, 3, 3, 3, 3, 3]
line [11, 9, 7, 5, 3, 1, -1, -3]

现在这看起来并没有那么令人兴奋。它只是把类型为 f(a,b,c) 的函数调用替换成了类型为 f(a)(b)(c) 的调用,这在Python中甚至可能被认为是比较不优雅的写法。

但它让你可以这样做:

line_through_zero = simple_function(0)
print('line through zero {}'.format(line_through_zero(1)(x))) # only slope and x

结果是

line through zero [-4, -3, -2, -1, 0, 1, 2, 3]

所以,柯里化的好处在于你可以得到一些固定参数的专门化函数,这样就可以用这些函数代替每次都写更一般形式并设置参数的麻烦。

柯里化的替代方法有: partiallambda默认参数。所以在实际使用中,柯里化可能会有用,但如果你想,也可以找到其他方法来解决问题。

更多内容请见 Python中的柯里化

撰写回答