我经常在网上看到各种各样的抱怨,说其他人的套用例子并不是套用,而实际上只是部分应用。
我还没有找到一个像样的解释来解释什么是部分应用,或者它与咖喱有什么不同。这似乎是一种普遍的混淆,类似的例子在一些地方被描述为套用,在另一些地方被描述为部分应用。
谁能给我提供这两个术语的定义,以及它们之间的区别?
我经常在网上看到各种各样的抱怨,说其他人的套用例子并不是套用,而实际上只是部分应用。
我还没有找到一个像样的解释来解释什么是部分应用,或者它与咖喱有什么不同。这似乎是一种普遍的混淆,类似的例子在一些地方被描述为套用,在另一些地方被描述为部分应用。
谁能给我提供这两个术语的定义,以及它们之间的区别?
当前回答
注意:本文摘自f# Basics,这是一篇非常好的介绍性文章,供。net开发人员学习函数式编程。
Currying means breaking a function with many arguments into a series of functions that each take one argument and ultimately produce the same result as the original function. Currying is probably the most challenging topic for developers new to functional programming, particularly because it is often confused with partial application. You can see both at work in this example: let multiply x y = x * y let double = multiply 2 let ten = double 5 Right away, you should see behavior that is different from most imperative languages. The second statement creates a new function called double by passing one argument to a function that takes two. The result is a function that accepts one int argument and yields the same output as if you had called multiply with x equal to 2 and y equal to that argument. In terms of behavior, it’s the same as this code: let double2 z = multiply 2 z Often, people mistakenly say that multiply is curried to form double. But this is only somewhat true. The multiply function is curried, but that happens when it is defined because functions in F# are curried by default. When the double function is created, it’s more accurate to say that the multiply function is partially applied. The multiply function is really a series of two functions. The first function takes one int argument and returns another function, effectively binding x to a specific value. This function also accepts an int argument that you can think of as the value to bind to y. After calling this second function, x and y are both bound, so the result is the product of x and y as defined in the body of double. To create double, the first function in the chain of multiply functions is evaluated to partially apply multiply. The resulting function is given the name double. When double is evaluated, it uses its argument along with the partially applied value to create the result.
其他回答
我在另一个帖子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和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是一个只有一个参数的函数,它接受一个函数f,并返回一个新函数h。注意,h接受一个X的参数,并返回一个将Y映射到Z的函数:
curry(f) = h
f: (X x Y) -> Z
h: X -> (Y -> Z)
部分应用是一个有两个(或多个)参数的函数,它接受一个函数f和一个或多个附加参数,并返回一个新函数g:
part(f, 2) = g
f: (X x Y) -> Z
g: Y -> Z
出现混淆是因为对于一个双参数函数,下面的等式成立:
partial(f, a) = curry(f)(a)
两边都将产生相同的单参数函数。
对于更高的函数,相等性不成立,因为在这种情况下,curry将返回一个单参数函数,而partial应用将返回一个多参数函数。
不同之处在于行为上,curry会递归地转换整个原始函数(每个参数一次),而局部应用只是一步替换。
来源:维基百科。
有趣的问题。经过一番搜索,“部分函数应用程序不是咖喱”给出了我找到的最好的解释。我不能说实际的区别对我来说特别明显,但我不是一个FP专家……
另一个看起来很有用的页面(我承认我还没有完全读完)是“用Java闭包curry和Partial Application”。
注意,这看起来确实是一对被广泛混淆的术语。