部分应用和关闭

Eig*_*rew 8 closures partial

我被问到部分功能应用程序和闭包之间的关系是什么.我会说没有,除非我忽略了这一点.假设我正在用python编写,我有一个非常简单的函数MySum定义如下:

MySum = lambda x, y : x + y;
Run Code Online (Sandbox Code Playgroud)

现在我正在修复一个参数以获得一个较小arity的函数,如果我使用相同的参数(部分应用程序)调用它,则返回MySum返回的相同值:

MyPartialSum = lambda x : MySum(x, 0);
Run Code Online (Sandbox Code Playgroud)

我可以用C做同样的事情:

int MySum(int x, int y) { return x + y; }
int MyPartialSum(int x) { return MySum(x, 0); }
Run Code Online (Sandbox Code Playgroud)

所以,愚蠢的问题是:有什么区别?为什么我需要关闭部分应用程序?这些代码是等价的,我不知道闭包和部分应用的界限是什么.

小智 7

部分函数应用程序是关于固定给定函数的一些参数以产生另一个参数较少的函数,例如

sum = lambda x, y: x + y
inc = lambda x: sum(x, 1)
Run Code Online (Sandbox Code Playgroud)

请注意, 'inc' 是部分应用的 'sum',没有从上下文中捕获任何内容(如您提到的闭包)。

但是,这种手写(通常是匿名的)函数有点乏味。可以使用函数工厂,它返回一个内部函数。内部函数可以通过从其上下文中捕获一些变量来参数化,例如

# sum = lambda x, y: x + y
def makePartialSumF(n):
    def partialSumF(x):
        return sum(x, n)
    return partialSumF

inc = makePartialSumF(1)
plusTwo = makePartialSumF(2)
Run Code Online (Sandbox Code Playgroud)

这里工厂 makePartialSumF 被调用两次。每次调用都会产生一个 partialSumF 函数(将不同的值捕获为 n)。使用闭包可以方便地实现偏应用。所以你可以说部分应用可以通过闭包的方式来实现。当然,闭包可以做很多其他的事情!(作为一个侧节点,python 没有适当的闭包。)

柯里化是关于将包含 N 个参数的函数转换为返回一元函数的一元函数……例如,我们有一个接受三个参数并返回一个值的函数:

sum = lambda x, y, z: x + y + z
Run Code Online (Sandbox Code Playgroud)

咖喱版本是

curriedSum = lambda x: lambda y: lambda z: x + y + z
Run Code Online (Sandbox Code Playgroud)

我打赌你不会写那样的python代码。IMO Currying的动机主要是理论上的兴趣。(一个只使用一元函数表达计算的框架:每个函数都是一元的!)实际的副产品是,在函数被柯里化的语言中,一些部分应用(当你从左边“修复”参数时)就像提供参数一样微不足道到咖喱函数。(但并非所有偏应用都是如此。例如:给定 f(x,y,z) = x+2*y+3*z,当您将 y 绑定到一个常量以产生两个变量的函数时。)所以你可以说,柯里化是一种技术,在实践中作为副产品,它可以使许多有用的部分功能应用变得微不足道,但这不是柯里化的重点。


Ham*_*ish 5

部分应用是一种技术,通过它您可以采用现有函数及其参数的子集,并生成一个接受剩余参数的新函数。

换句话说,如果你有 function F(a, b),一个应用部分应用的函数a看起来像B(fn, a)where F(a, b) = B(F, a)(b)

在您的示例中,您只是创建新函数,而不是将部分应用程序应用于现有函数。

这是python中的一个例子:

def curry_first(fn, arg):
    def foo(*args):
       return fn(arg, *args)
    return foo
Run Code Online (Sandbox Code Playgroud)

这会在提供的函数和参数上创建一个闭包。返回一个新函数,该函数调用具有新参数签名的第一个函数。闭包很重要 - 它允许fn访问arg. 现在你可以做这样的事情:

add = lambda x, y : x + y;
add2 = curry_first(add, 2)
add2(4) # returns 6
Run Code Online (Sandbox Code Playgroud)

我通常听说这被称为currying

  • @Hamish Currying 不是一回事。柯里化将在每一步返回一个嵌套的函数链,而部分应用程序返回一个采用缺失参数的函数,其中已提供的参数被所提供的值替换。 (2认同)