我在一些文章和博客中看到了curry函数的引用,但我找不到一个好的解释(或者至少一个有意义的解释!)


当前回答

curry函数是一个由几个参数重写的函数,它接受第一个参数,并返回一个接受第二个参数的函数,以此类推。这允许具有多个参数的函数部分应用它们的初始参数。

其他回答

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。

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是指将一个N次的函数转换为N次1次的函数。函数的元数是它所需要的参数的个数。

下面是正式的定义:

 curry(f) :: (a,b,c) -> f(a) -> f(b)-> f(c)

下面是一个真实的例子:

你去自动取款机取钱。你刷你的卡,输入密码,做出选择,然后按enter键提交“金额”和请求。

这是取款的正常功能。

const withdraw=(cardInfo,pinNumber,request){
    // process it
       return request.amount
}

在这个实现函数中,我们希望一次性输入所有参数。我们将刷卡,输入密码并发出请求,然后函数将运行。如果这些步骤中有任何问题,在输入所有参数后就会发现。使用curry函数,我们可以创建更高的、纯粹的和简单的函数。纯函数将帮助我们轻松地调试代码。

这是带有咖喱功能的Atm机。

const withdraw=(cardInfo)=>(pinNumber)=>(request)=>request.amount

ATM, takes the card as input and returns a function that expects pinNumber and this function returns a function that accepts the request object and after the successful process, you get the amount that you requested. Each step, if you had an error, you will easily predict what went wrong. Let's say you enter the card and got error, you know that it is either related to the card or machine but not the pin number. Or if you entered the pin and if it does not get accepted you know that you entered the pin number wrong. You will easily debug the error.

此外,这里的每个函数都是可重用的,因此您可以在项目的不同部分使用相同的函数。

正如所有其他答案一样,咖喱有助于创建部分应用函数。Javascript不提供自动咖喱的原生支持。因此,上面提供的示例可能对实际编码没有帮助。在livescript中有一些很好的例子(基本上编译成js) http://livescript.net/

times = (x, y) --> x * y
times 2, 3       #=> 6 (normal use works as expected)
double = times 2
double 5         #=> 10

在上面的例子中,当你给出较少的no of参数时,livescript会为你生成新的curried函数(double)

curry是一种可以应用于函数的转换,允许它们比以前少接受一个参数。

例如,在f#中你可以这样定义一个函数:-

let f x y z = x + y + z

这里函数f取参数x, y和z,并将它们相加:-

f 1 2 3

返回6。

根据我们的定义,我们可以定义f的curry函数:-

let curry f = fun x -> f x

其中'fun x - >fx '是一个lambda函数,在c#中等价于x => f(x)。此函数输入您希望curry的函数,并返回一个接受单个参数的函数,并返回指定的函数,其中第一个参数设置为输入参数。

使用前面的例子,我们可以得到f的curry值:-

let curryf = curry f

然后我们可以做以下的事情:-

let f1 = curryf 1

这为我们提供了一个函数f1,它等价于f1 y z = 1 + y + z。这意味着我们可以做以下事情

f1 2 3

返回6。

这个过程经常与“部分函数应用”相混淆,可以这样定义:-

let papply f x = f x

尽管我们可以将其扩展为多个参数,即:-

let papply2 f x y = f x y
let papply3 f x y z = f x y z
etc.

部分应用程序将接受函数和形参并返回一个需要一个或多个更少形参的函数,正如前面两个示例所示,它直接在标准f#函数定义中实现,因此我们可以通过以下方式实现前面的结果

let f1 = f 1
f1 2 3

它将返回一个6的结果。

结论:-

咖喱和部分函数应用的区别是:-

curry接受一个函数,并提供一个接受单个参数的新函数,并返回指定函数,并将其第一个参数设置为该参数。这允许我们将具有多个形参的函数表示为一系列单实参函数。例子:-

let f x y z = x + y + z
let curryf = curry f
let f1 = curryf 1
let f2 = curryf 2
f1 2 3
6
f2 1 3
6

偏函数应用更直接——它接受一个函数和一个或多个参数,并返回一个函数,其中前n个参数设置为指定的n个参数。例子:-

let f x y z = x + y + z
let f1 = f 1
let f2 = f 2
f1 2 3
6
f2 1 3
6