我在一些文章和博客中看到了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是指将一个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)

有一个“咖喱在理性ml”的例子。

let run = () => {
    Js.log("Curryed function: ");
    let sum = (x, y) => x + y;
    Printf.printf("sum(2, 3) : %d\n", sum(2, 3));
    let per2 = sum(2);
    Printf.printf("per2(3) : %d\n", per2(3));
  };

如果你理解了部分,你就成功了一半。partial的思想是将参数预先应用到一个函数,并返回一个只需要剩余参数的新函数。当这个新函数被调用时,它包括预加载的参数以及提供给它的任何参数。

在Clojure +中是一个函数,但要明确一点:

(defn add [a b] (+ a b))

您可能已经意识到inc函数只是简单地将1加到它传递的任何数字上。

(inc 7) # => 8

让我们自己使用partial来构建它:

(def inc (partial add 1))

Here we return another function that has 1 loaded into the first argument of add. As add takes two arguments the new inc function wants only the b argument -- not 2 arguments as before since 1 has already been partially applied. Thus partial is a tool from which to create new functions with default values presupplied. That is why in a functional language functions often order arguments from general to specific. This makes it easier to reuse such functions from which to construct other functions.

现在想象一下,如果语言足够聪明,能够自省地理解add需要两个参数。当我们向它传递一个参数时,如果函数部分应用了我们代表它传递的参数,并理解我们可能打算稍后提供另一个参数呢?然后,我们可以在不显式使用partial的情况下定义inc。

(def inc (add 1)) #partial is implied

这是一些语言的表现方式。当希望将函数组合成更大的转换时,它特别有用。这将把人们引向传感器。

下面是泛型和最短版本的函数用n no curry的例子。的参数。

const add = a => b => b ? add(a + b) : a; 

Const add = a => b => b ?Add (a + b): a; console.log(添加(1)(2)(3)(4)());