我经常在网上看到各种各样的抱怨,说其他人的套用例子并不是套用,而实际上只是部分应用。
我还没有找到一个像样的解释来解释什么是部分应用,或者它与咖喱有什么不同。这似乎是一种普遍的混淆,类似的例子在一些地方被描述为套用,在另一些地方被描述为部分应用。
谁能给我提供这两个术语的定义,以及它们之间的区别?
我经常在网上看到各种各样的抱怨,说其他人的套用例子并不是套用,而实际上只是部分应用。
我还没有找到一个像样的解释来解释什么是部分应用,或者它与咖喱有什么不同。这似乎是一种普遍的混淆,类似的例子在一些地方被描述为套用,在另一些地方被描述为部分应用。
谁能给我提供这两个术语的定义,以及它们之间的区别?
当前回答
局部套用
维基百科上说
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)
其他回答
注意:本文摘自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.
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会递归地转换整个原始函数(每个参数一次),而局部应用只是一步替换。
来源:维基百科。
我假设大多数问这个问题的人已经熟悉了基本概念,所以他们没有必要谈论这个。重叠是令人困惑的部分。
您可能能够充分使用这些概念,但您将它们一起理解为伪原子无定形的概念模糊。现在缺少的是知道它们之间的界限在哪里。
与其定义它们是什么,不如简单地强调它们的不同之处——边界。
curry是在定义函数的时候。
部分应用程序是在调用函数时。
应用程序是调用函数的数学术语。
部分应用程序需要调用一个curry函数并获得一个函数作为返回类型。
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和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分钟 咖喱:与部分函数应用的对比