我经常在网上看到各种各样的抱怨,说其他人的套用例子并不是套用,而实际上只是部分应用。
我还没有找到一个像样的解释来解释什么是部分应用,或者它与咖喱有什么不同。这似乎是一种普遍的混淆,类似的例子在一些地方被描述为套用,在另一些地方被描述为部分应用。
谁能给我提供这两个术语的定义,以及它们之间的区别?
我经常在网上看到各种各样的抱怨,说其他人的套用例子并不是套用,而实际上只是部分应用。
我还没有找到一个像样的解释来解释什么是部分应用,或者它与咖喱有什么不同。这似乎是一种普遍的混淆,类似的例子在一些地方被描述为套用,在另一些地方被描述为部分应用。
谁能给我提供这两个术语的定义,以及它们之间的区别?
当前回答
这里的很多人都没有正确地解决这个问题,也没有人谈论过重叠。
简单的答案
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);
命名约定
等我有时间再写,很快就有时间了。
其他回答
要了解它们的不同之处,最简单的方法是考虑一个真实的例子。让我们假设我们有一个函数Add,它接受2个数字作为输入,并返回一个数字作为输出,例如Add(7,5)返回12。在这种情况下:
Partial applying the function Add with a value 7 will give us a new function as output. That function itself takes 1 number as input and outputs a number. As such: Partial(Add, 7); // returns a function f2 as output // f2 takes 1 number as input and returns a number as output So we can do this: f2 = Partial(Add, 7); f2(5); // returns 12; // f2(7)(5) is just a syntactic shortcut Currying the function Add will give us a new function as output. That function itself takes 1 number as input and outputs yet another new function. That third function then takes 1 number as input and returns a number as output. As such: Curry(Add); // returns a function f2 as output // f2 takes 1 number as input and returns a function f3 as output // i.e. f2(number) = f3 // f3 takes 1 number as input and returns a number as output // i.e. f3(number) = number So we can do this: f2 = Curry(Add); f3 = f2(7); f3(5); // returns 12
换句话说,“套用”和“局部应用”是两种完全不同的功能。curry只需要1个输入,而partial应用程序需要2个(或更多)输入。
尽管它们都返回一个函数作为输出,但返回的函数是完全不同的形式,如上所述。
在写这篇文章时,我混淆了咖喱和不咖喱。它们是函数的逆变换。不管你怎么称呼它,只要你知道这个变换和它的逆代表什么。
不咖喱的定义不是很清楚(或者说,有“冲突”的定义都抓住了这个想法的精神)。基本上,这意味着将一个接受多个参数的函数转换为一个接受单个参数的函数。例如,
(+) :: Int -> Int -> Int
现在,你如何把它变成一个只有一个参数的函数呢?你当然作弊了!
plus :: (Int, Int) -> Int
注意,加号现在只有一个参数(由两件事组成)。超级!
这有什么意义?好吧,如果你有一个带两个参数的函数,你有一对参数,知道你可以把函数应用到参数上,并且仍然得到你想要的是很好的。事实上,这样做的管道已经存在,所以你不需要做像显式模式匹配这样的事情。你所要做的就是:
(uncurry (+)) (1,2)
什么是偏函数应用?将有两个参数的函数转换为只有一个参数的函数是另一种方法。但它的工作方式不同。同样,让我们以(+)为例。我们如何将它转换为一个以单个Int作为参数的函数?我们作弊!
((+) 0) :: Int -> Int
这是一个函数,将0加到任何Int。
((+) 1) :: Int -> Int
对任意Int值加1。等。在每一种情况下,(+)是“部分应用”。
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分钟 咖喱:与部分函数应用的对比
局部套用
维基百科上说
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)
我在另一个帖子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
为了柯里林。