我在一些文章和博客中看到了curry函数的引用,但我找不到一个好的解释(或者至少一个有意义的解释!)
当前回答
curry是将函数从可调用的f(a, b, c)转换为可调用的f(a)(b)(c)。
另外,curry是指将一个接受多个参数的函数分解为一系列接受部分参数的函数。
从字面上看,curry是函数的转换:从一种调用方式到另一种调用方式。在JavaScript中,我们通常创建一个包装器来保留原始函数。
curry不调用函数。它只是变换了它。
让我们创建一个curry函数,它对双实参函数执行curry。换句话说,对于双参数f(a, b)的curry(f)将其转换为f(a)(b)
function curry(f) { // curry(f) does the currying transform
return function(a) {
return function(b) {
return f(a, b);
};
};
}
// usage
function sum(a, b) {
return a + b;
}
let carriedSum = curry(sum);
alert( carriedSum(1)(2) ); // 3
如您所见,实现是一系列的包装器。
curry(func)的结果是一个包装器函数(a)。 当它像sum(1)一样被调用时,参数被保存在词法环境中,并返回一个新的包装器函数(b)。 然后sum(1)(2)最后调用函数(b)提供2,它将调用传递给原始的多参数sum。
其他回答
curry函数应用于多个参数列表,而不仅仅是 一个。
这是一个常规的、非咖喱的函数,它加了两个Int 参数x和y:
scala> def plainOldSum(x: Int, y: Int) = x + y
plainOldSum: (x: Int,y: Int)Int
scala> plainOldSum(1, 2)
res4: Int = 3
这是一个类似的咖喱函数。而不是 对于一个包含两个Int形参的列表,您将此函数应用于两个包含一个Int形参的列表 Int参数each:
scala> def curriedSum(x: Int)(y: Int) = x + y
curriedSum: (x: Int)(y: Int)Intscala> second(2)
res6: Int = 3
scala> curriedSum(1)(2)
res5: Int = 3
这里发生的事情是,当您调用curriedSum时,实际上会得到两个背对背的传统函数调用。第一个函数 调用接受一个名为x的Int形参,并返回一个函数 为第二个函数。第二个函数接受Int形参 y。
这里有一个名为first的函数,它在精神上完成了第一个传统函数 函数调用curriedSum会做:
scala> def first(x: Int) = (y: Int) => x + y
first: (x: Int)(Int) => Int
对第一个函数应用1——换句话说,调用第一个函数 而传入1 -会得到第二个函数:
scala> val second = first(1)
second: (Int) => Int = <function1>
对第二个函数应用2得到的结果是:
scala> second(2)
res6: Int = 3
“Currying”是一个获取多个参数的函数并将其转换为一系列函数的过程,每个函数接受一个参数并返回一个参数的函数,或者在最终函数的情况下,返回实际结果。
curry是指将一个接受多个参数的函数分解为一系列函数,每个函数只接受一个参数。下面是JavaScript的一个例子:
function add (a, b) {
return a + b;
}
add(3, 4); // returns 7
这是一个接受两个参数a和b的函数,并返回它们的和。现在我们将咖喱这个函数:
function add (a) {
return function (b) {
return a + b;
}
}
这是一个接受一个参数a的函数,并返回一个接受另一个参数b的函数,该函数返回它们的和。
add(3)(4); // returns 7
var add3 = add(3); // returns a function
add3(4); // returns 7
第一个语句返回7,就像add(3,4)语句一样。 第二条语句定义了一个名为add3的新函数 给它的参数加上3。(这就是有些人所说的终结。) 第三条语句再次使用add3操作将3添加到4 结果是7。
它可以是一种用函数生成其他函数的方法。
在javascript中:
let add = function(x){
return function(y){
return x + y
};
};
我们可以这样称呼它:
let addTen = add(10);
运行时,将10作为x传入;
let add = function(10){
return function(y){
return 10 + y
};
};
这意味着我们返回这个函数:
function(y) { return 10 + y };
所以当你打电话的时候
addTen();
你真的在呼唤:
function(y) { return 10 + y };
如果你这样做:
addTen(4)
这就相当于:
function(4) { return 10 + 4} // 14
所以我们的addTen()总是给我们传入的任何东西加10。我们可以用同样的方法来构造类似的函数:
let addTwo = add(2) // addTwo(); will add two to whatever you pass in
let addSeventy = add(70) // ... and so on...
接下来的问题是,你到底为什么要这么做?它将一个急迫的操作x + y变成了一个可以轻松完成的操作,这意味着我们至少可以做两件事 1. 缓存昂贵的操作 2. 在功能范式中实现抽象。
想象我们的咖喱函数是这样的:
let doTheHardStuff = function(x) {
let z = doSomethingComputationallyExpensive(x)
return function (y){
z + y
}
}
我们可以调用这个函数一次,然后将结果传递给很多地方,这意味着我们只做一次计算上昂贵的事情:
let finishTheJob = doTheHardStuff(10)
finishTheJob(20)
finishTheJob(30)
我们可以用类似的方式得到抽象。
下面是Python中的一个小例子:
>>> from functools import partial as curry
>>> # Original function taking three parameters:
>>> def display_quote(who, subject, quote):
print who, 'said regarding', subject + ':'
print '"' + quote + '"'
>>> display_quote("hoohoo", "functional languages",
"I like Erlang, not sure yet about Haskell.")
hoohoo said regarding functional languages:
"I like Erlang, not sure yet about Haskell."
>>> # Let's curry the function to get another that always quotes Alex...
>>> am_quote = curry(display_quote, "Alex Martelli")
>>> am_quote("currying", "As usual, wikipedia has a nice summary...")
Alex Martelli said regarding currying:
"As usual, wikipedia has a nice summary..."
(只是通过+来使用连接,以避免非python程序员分心。)
编辑添加:
看到http://docs.python.org/library/functools.html?highlight=partial functools.partial, 这也显示了Python实现的部分对象和函数的区别。