我经常在网上看到各种各样的抱怨,说其他人的套用例子并不是套用,而实际上只是部分应用。

我还没有找到一个像样的解释来解释什么是部分应用,或者它与咖喱有什么不同。这似乎是一种普遍的混淆,类似的例子在一些地方被描述为套用,在另一些地方被描述为部分应用。

谁能给我提供这两个术语的定义,以及它们之间的区别?


当前回答

我在另一个帖子https://stackoverflow.com/a/12846865/1685865中回答了这个问题。简而言之,部分函数应用是关于固定一个给定的多变量函数的一些参数,以产生另一个具有更少参数的函数,而Currying是关于将一个有N个参数的函数转换为一个返回一元函数的一元函数…[一个curry的例子显示在这篇文章的最后。]

curry主要是理论方面的兴趣:可以只用一元函数来表示计算(即每个函数都是一元函数)。在实践中,它是一种技术,可以使许多有用的(但不是全部)部分函数式应用程序变得微不足道,如果语言有咖喱函数的话。同样,它不是实现部分应用程序的唯一方法。所以你可能会遇到这样的情况,部分应用程序是用其他方式完成的,但人们会把它误认为是curry。

(以咖喱为例)

在实践中,人们不只是写

lambda x: lambda y: lambda z: x + y + z

或者等价的javascript

function (x) { return function (y){ return function (z){ return x + y + z }}}

而不是

lambda x, y, z: x + y + z

为了柯里林。

其他回答

这里的很多人都没有正确地解决这个问题,也没有人谈论过重叠。

简单的答案

curry:让你调用一个函数,把它分成多个调用,每次调用提供一个参数。

部分应用:允许你调用一个函数,把它分成多个调用,每次调用提供多个参数。

两者之间的重要区别之一是调用 部分应用的函数立即返回结果,而不是另一个 沿着咖喱链;这种区别可以用例子来说明 显然,对于集度大于2的函数。

这是什么意思?这意味着对一个局部函数最多有两次调用。curry的参数和参数的数量一样多。如果curry函数只有两个参数,那么它本质上与偏函数相同。

例子

部分应用和咖喱

function bothPartialAndCurry(firstArgument) {
    return function(secondArgument) {
        return firstArgument + secondArgument;
    }
}

const partialAndCurry = bothPartialAndCurry(1);
const result = partialAndCurry(2);

部分应用程序

function partialOnly(firstArgument, secondArgument) {
    return function(thirdArgument, fourthArgument, fifthArgument) {
        return firstArgument + secondArgument + thirdArgument + fourthArgument + fifthArgument;
    }
}

const partial = partialOnly(1, 2);
const result = partial(3, 4, 5);

局部套用

function curryOnly(firstArgument) {
    return function(secondArgument) {
        return function(thirdArgument) {
            return function(fourthArgument ) {
                return function(fifthArgument) {
                    return firstArgument + secondArgument + thirdArgument + fourthArgument + fifthArgument;
                }
            }
        }
    }
}

const curryFirst = curryOnly(1);
const currySecond = curryFirst(2);
const curryThird = currySecond(3);
const curryFourth = curryThird(4);
const result = curryFourth(5);

// or...

const result = curryOnly(1)(2)(3)(4)(5);

命名约定

等我有时间再写,很快就有时间了。

curry是将一个有n个参数的函数转换为n个每个函数都有一个参数的函数。给定以下函数:

function f(x,y,z) { z(x(y));}

咖喱后,变成:

function f(x) { lambda(y) { lambda(z) { z(x(y)); } } }

为了得到f(x,y,z)的完整应用,你需要这样做:

f(x)(y)(z);

许多函数式语言允许你写fx y z。如果你只调用fx y或f(x)(y),那么你会得到一个部分应用的函数——返回值是lambda(z){z(x(y))}的闭包,将x和y的值传递给f(x,y)。

使用部分应用的一种方法是将函数定义为广义函数的部分应用,如fold:

function fold(combineFunction, accumulator, list) {/* ... */}
function sum     = curry(fold)(lambda(accum,e){e+accum}))(0);
function length  = curry(fold)(lambda(accum,_){1+accum})(empty-list);
function reverse = curry(fold)(lambda(accum,e){concat(e,accum)})(empty-list);

/* ... */
@list = [1, 2, 3, 4]
sum(list) //returns 10
@f = fold(lambda(accum,e){e+accum}) //f = lambda(accumulator,list) {/*...*/}
f(0,list) //returns 10
@g = f(0) //same as sum
g(list)  //returns 10

局部套用

维基百科上说

curry是一种将带有多个参数的函数转换为带有单个参数的函数序列的技术。

例子

const add = (a, b) => a + b

const addC = (a) => (b) => a + b // curried function. Where C means curried

部分应用程序

文章刚刚好FP:部分应用

部分应用是将部分(而不是全部)参数应用到函数,并返回一个新函数等待其余参数。这些应用的参数存储在闭包中,并且将来对任何部分应用的返回函数仍然可用。

例子

const add = (a) => (b) => a + b

const add3 = add(3) // add3 is a partially applied function

add3(5) // 8

区别在于

咖喱是一种技术(模式) Partial application是一个带有一些预定义参数的函数(如前面示例中的add3)

curry和partial application之间的区别可以通过下面的JavaScript示例来最好地说明:

function f(x, y, z) {
    return x + y + z;
}

var partial = f.bind(null, 1);

6 === partial(2, 3);

局部应用的结果是一个更小的函数;在上面的例子中,f的arity是3,而partial的arity只有2。更重要的是,部分应用的函数将在被调用时立即返回结果,而不是沿着curry链向下的另一个函数。所以如果你看到的是偏(2)偏(3),实际上这不是偏应用。

进一步阅读:

函数式编程5分钟 咖喱:与部分函数应用的对比

有趣的问题。经过一番搜索,“部分函数应用程序不是咖喱”给出了我找到的最好的解释。我不能说实际的区别对我来说特别明显,但我不是一个FP专家……

另一个看起来很有用的页面(我承认我还没有完全读完)是“用Java闭包curry和Partial Application”。

注意,这看起来确实是一对被广泛混淆的术语。