【问题标题】:When should I use function currying?我什么时候应该使用函数柯里化?
【发布时间】:2014-09-12 22:23:08
【问题描述】:

When should I write my functions in curried form?与我的想法不符,需要改正。

作为我学习link 的一部分,这是我从函数柯里化中理解的。下面是一个例子:

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(say),然后我将定义def normalise_range(x, y):函数并通过调用normalise_range(x, y)直接在我的应用程序中使用它。

在任何应用程序中,如果我知道,参数的数量是固定的(比如 2 个参数), 但函数名称不同(可以是normalise_range/average/我不知道..), 然后我将使用def curry2(f):,如上所示,它将接受所有带两个参数的函数(固定)。

我的问题:

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

【问题讨论】:

  • 为什么你决定是否使用一个函数与你是否提前知道名字有关?只要你可以打电话给curry2(f),你就可以打电话给f(x, y)而不用curry。
  • @user2357112 我明白你的意思了。
  • @Trilarion 让我先了解一下,什么时候使用函数柯里化,然后我会想到比较Function Curryingpartial application

标签: python functional-programming


【解决方案1】:

函数柯里化的目的是从更通用的函数中轻松获得专门的函数。您可以通过在不同时间预先设置一些参数并在之后保持它们固定来实现这一点。

这与命名无关。在 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]

因此,currying 的优点是您可以获得具有固定参数并且可以使用的专用函数,而不是编写更通用的形式并在每次调用时设置固定参数。

柯里化的替代方案是:partiallambdadefault parameters。所以在实践中,柯里化可能很有用,但如果你愿意,你也可以绕过它。

另见Currying in Python

【讨论】:

  • 拥有专门的功能有什么好处(例如,line_through_zero 在你的答案中)?现在,我认为,currying 可能很有用,在我们有 3 个参数(比如)并且第一个参数准备好(比如)的情况下,所以我们在应用一个参数后创建专门的函数并等待来自第三方模块的其他两个参数(比如)。你认为我们可以有这样的场景吗?
  • 我的意思是,如果一个函数有两个参数,那么第一个参数在 place1 可用,然后部分应用的函数被创建并多次传递到第二个参数可用的 place2。我对吗?
  • “因此,currying 的优点是您可以获得具有固定参数的专用函数,并且可以使用它来代替编写更通用的形式并在每次调用时设置固定的参数。” ——这种说法虽然是对的,但却埋葬了海事组织。 main 的优点是它允许通过 composition 创建新功能。
【解决方案2】:

Currying 至少有两个我能想到的优点:

1) 它保留您的代码(以及您的思考DRY

假设你有这样的功能:

def call_me(context, args):
    ...

通过currying,您可以获得context 的专用函数,可以随意折腾等等。您不必再次重复上下文。

2) 考虑单个输入函数比n 参数容易得多;不过,这有时是值得商榷的。

另见:What is the difference between currying and partial application?

【讨论】:

    【解决方案3】:

    在许多方面,这种柯里化和将参数部分应用于函数的组合模拟了面向对象编程中我们称之为“工厂模式”的内容。正如其他人在本论坛中指出的那样,Currying 允许程序员创建专门的函数。例如,检查下面的快速排序的这个(不是优雅的)实现:

    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]))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-07
      • 2012-09-22
      • 1970-01-01
      • 2020-05-29
      • 2012-12-23
      • 2021-07-13
      • 1970-01-01
      相关资源
      最近更新 更多