Functional programming 什么是';咖喱;?

Functional programming 什么是';咖喱;?,functional-programming,terminology,definition,currying,Functional Programming,Terminology,Definition,Currying,我在几篇文章和博客中看到了对curry函数的引用,但我找不到一个好的解释(或者至少有一个解释是有意义的!)curry是指将一个包含多个参数的函数分解为一系列只包含一个参数的函数。下面是一个JavaScript示例: 功能添加(a、b){ 返回a+b; } 加上(3,4);//返回7 这是一个函数,它接受两个参数a和b,并返回它们的和。我们现在将使用此函数: scala> val second = first(1) second: (Int) => Int = <functio

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

curry是指将一个包含多个参数的函数分解为一系列只包含一个参数的函数。下面是一个JavaScript示例:

功能添加(a、b){
返回a+b;
}
加上(3,4);//返回7
这是一个函数,它接受两个参数a和b,并返回它们的和。我们现在将使用此函数:

scala> val second = first(1)
second: (Int) => Int = <function1>
const withdraw=(cardInfo)=>(pinNumber)=>(request)=>request.amount
函数添加(a){
返回函数(b){
返回a+b;
}
}
这是一个函数,它接受一个参数
a
,并返回一个接受另一个参数
b
,该函数返回它们的和

增加(3)(4);
var add3=添加(3);
增补3(4);

第一条语句返回7,就像
add(3,4)
语句一样。第二条语句定义了一个名为
add3
的新函数,该函数将在其参数中添加3。(有些人可能称之为闭包。)第三条语句使用
add3
操作将3添加到4,结果再次生成7。

Currying是一种转换,可以应用于函数,以允许它们比以前少取一个参数

例如,在F#中,您可以这样定义函数:-

设f x y z=x+y+z
这里,函数f取参数x、y和z,并将它们相加,以便:-

f123
返回6

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

让咖喱f=funx->fx
其中'funx->fx'是与C#中的x=>f(x)等价的lambda函数。此函数输入您希望使用的函数,并返回一个函数,该函数接受一个参数,并返回指定的函数,其中第一个参数设置为输入参数

使用我们前面的例子,我们可以得到一个f的咖喱,因此:-

让curryf=curry f
然后,我们可以执行以下操作:-

设f1=curryf 1
它为我们提供了一个函数f1,它等价于f1 y z=1+y+z。这意味着我们可以做到以下几点:-

f1 2 3
返回6

这一过程经常与“部分功能应用”相混淆,后者可以这样定义:-

让papply fx=fx
虽然我们可以将其扩展到多个参数,即:-

设papply2 f x y=f x y
设papply3 f x y z=f x y z
等
部分应用程序将获取函数和参数,并返回需要一个或多个较少参数的函数,如前两个示例所示,该函数直接在标准F#函数定义中实现,因此我们可以实现之前的结果:-

设f1=f1
f1 2 3
这将返回6的结果

总之:-

curry和partial函数应用的区别在于:-


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

设f x y z=x+y+z
设curryf=curryf
设f1=curryf 1
设f2=curryf 2
f1 2 3
6.
f2 1 3
6.
分部函数应用程序更直接—它接受一个函数和一个或多个参数,并返回一个函数,其中前n个参数设置为指定的n个参数。例如:-

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

curried函数是一个包含多个参数的函数,重写后的函数接受第一个参数并返回一个接受第二个参数的函数,依此类推。这使得具有多个参数的函数可以部分应用其初始参数。

在函数代数中,处理具有多个参数的函数(或相当于N元组的一个参数)有点不雅观——但是,正如摩西·舍芬克尔(以及独立的哈斯克尔·库里)所证明的,不需要它:您只需要接受一个参数的函数

那么,如何处理自然表达为f(x,y)的东西呢?好吧,你把它看成是一个函数,你把它应用到
y
。换句话说,只有接受一个参数的函数——但其中一些函数返回其他函数(也接受一个参数;-)


与往常一样,它有一个关于这方面的很好的摘要条目,有许多有用的指针(可能包括关于您最喜欢的语言的指针;-)以及稍微更严格的数学处理。

我发现这篇文章及其引用的文章对更好地理解咖喱很有用:

正如其他人提到的,这只是一种拥有单参数函数的方法


这很有用,因为您不必假设将传入多少个参数,因此不需要2参数、3参数和4参数函数。

下面是一个具体示例:

假设你有一个计算作用在物体上的重力的函数。如果你不知道这个公式,你可以找到它。此函数接受三个必要的参数作为参数


现在,在地球上,你只想计算这个星球上物体的力。在函数式语言中,可以将地球质量传递给函数,然后对其进行部分计算。你得到的是另一个函数,它只需要两个参数,就可以计算出地球上物体的引力。这叫做咖喱。

这里有一个Python中的玩具示例:

>>从functools导入部分作为咖喱
>>>#采用三个参数的原始函数:
>>>def显示报价(谁、主题、报价)
scala> def first(x: Int) = (y: Int) => x + y
first: (x: Int)(Int) => Int
scala> val second = first(1)
second: (Int) => Int = <function1>
scala> second(2)
res6: Int = 3
(defn add [a b] (+ a b))
(inc 7) # => 8
(def inc (partial add 1))
(def inc (add 1)) #partial is implied
func aFunction(str: String) {
    let callback = callback(str) // signature now is `NSData -> ()`
    performAsyncRequest(callback)
}

func callback(str: String, data: NSData) {
    // Callback code
}

func performAsyncRequest(callback: NSData -> ()) {
    // Async code that will call callback with NSData as parameter
}
times = (x, y) --> x * y
times 2, 3       #=> 6 (normal use works as expected)
double = times 2
double 5         #=> 10
function curryMinus(x) 
{
  return function(y) 
  {
    return x - y;
  }
}

var minus5 = curryMinus(1);
minus5(3);
minus5(5);
var minus7 = curryMinus(7);
minus7(3);
minus7(5);
public static class FuncExtensions {
    public static Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(this Func<T1, T2, TResult> func)
    {
        return x1 => x2 => func(x1, x2);
    }
}

//Usage
var add = new Func<int, int, int>((x, y) => x + y).Curry();
var func = add(1);

//Obtaining the next parameter here, calling later the func with next parameter.
//Or you can prepare some base calculations at the previous step and then
//use the result of those calculations when calling the func multiple times 
//with different input parameters.

int result = func(1);
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
const add = a => b => b ? add(a + b) : a; 
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));
  };
const withdraw=(cardInfo,pinNumber,request){
    // process it
       return request.amount
}
const withdraw=(cardInfo)=>(pinNumber)=>(request)=>request.amount
const multiply = (presetConstant) => {
  return (x) => {
    return presetConstant * x;
  };
};

const multiplyByTwo = multiply(2);

// now multiplyByTwo is like below function & due to closure property in JavaScript it will always be able to access 'presetConstant' value
// const multiplyByTwo = (x) => {
//   return presetConstant * x;
// };

console.log(`multiplyByTwo(8) : ${multiplyByTwo(8)}`);