我在一些文章和博客中看到了curry函数的引用,但我找不到一个好的解释(或者至少一个有意义的解释!)
当前回答
我发现这篇文章,以及它引用的文章,有助于更好地理解咖喱: http://blogs.msdn.com/wesdyer/archive/2007/01/29/currying-and-partial-function-application.aspx
正如其他人所提到的,它只是一种具有单参数函数的方法。
这很有用,因为你不需要假设有多少参数将被传入,所以你不需要2个参数,3个参数和4个参数函数。
其他回答
这里有一个具体的例子:
假设你有一个计算作用在物体上的引力的函数。如果你不知道公式,你可以在这里找到。这个函数接受三个必要的形参作为参数。
现在,在地球上,你只想计算这个星球上物体的力。在函数式语言中,你可以把地球的质量传递给函数,然后对它进行部分计算。你会得到另一个函数,它只接受两个参数,并计算地球上物体的引力。这叫做咖喱。
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
curry的一个例子是当你有一个函数时,你现在只知道其中一个参数:
例如:
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
}
在这里,因为你不知道回调的第二个参数,当它发送给performAsyncRequest(_:)时,你必须创建另一个lambda /闭包来发送给函数。
在函数代数中,处理带有多个参数的函数(或相当于一个n元组的参数)有点不优雅——但是,正如Moses Schönfinkel(以及Haskell Curry)所证明的那样,这是不需要的:您所需要的只是带有一个参数的函数。
那么如何处理自然表示为f(x,y)的式子呢?好吧,你把它等价于f(x)(y)——f(x),叫它g,是一个函数,你把这个函数应用到y上。换句话说,你只有带一个参数的函数——但其中一些函数返回其他函数(也带一个参数;-)。
像往常一样,维基百科对此有一个很好的总结条目,有许多有用的指针(可能包括关于你最喜欢的语言的;-),以及稍微更严格的数学处理。
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.
此外,这里的每个函数都是可重用的,因此您可以在项目的不同部分使用相同的函数。