Ben*_*Ben 628 functional-programming terminology definition currying
我在几篇文章和博客中看到了对curried函数的引用,但我找不到一个好的解释(或者至少有一个有意义的解释!)
Kyl*_*nin 828
Currying是指您分解一个函数,该函数将多个参数带入一系列参数中的函数.这是JavaScript中的一个示例:
function add (a, b) {
return a + b;
}
add(3, 4); // returns 7
Run Code Online (Sandbox Code Playgroud)
这是一个带有两个参数a和b的函数,并返回它们的总和.我们现在将讨论这个功能:
function add (a) {
return function (b) {
return a + b;
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个函数,它接受一个参数a,并返回一个带有另一个参数b的函数,该函数返回它们的总和.
add(3)(4);
var add3 = add(3);
add3(4);
Run Code Online (Sandbox Code Playgroud)
第一个语句返回7,就像add(3,4)语句一样.第二个语句定义了一个名为add3的新函数,它将为其参数添加3.这是有些人可能称之为封闭的.第三个语句使用add3操作添加3到4,结果再次产生7.
Ale*_*lli 124
在函数的代数中,处理带有多个参数的函数(或等价的一个参数是一个N元组)有点不优雅 - 但是,正如MosesSchönfinkel(以及独立地,Haskell Curry)证明的那样,它不是必需的:所有你需要是一个参数的函数.
那么你如何处理你自然表达的事情f(x,y)呢?好吧,你把它当作 - 等同于f(x)(y)- f(x),调用它g,是一个函数,并将该函数应用于y.换句话说,你只有一个参数的函数 - 但其中一些函数返回其他函数(也可以带一个参数;-).
像往常一样,维基百科有一个很好的摘要条目,有许多有用的指针(可能包括关于你最喜欢的语言;-)以及稍微更严格的数学处理.
She*_*els 96
这是一个具体的例子:
假设您有一个计算作用在物体上的重力的函数.如果你不知道公式,你可以在这里找到它.此函数将三个必要参数作为参数.
现在,在地球上,你只想计算这个星球上物体的力量.在函数式语言中,您可以将地球的质量传递给函数,然后对其进行部分评估.你得到的是另一个只需要两个参数并计算地球上物体的引力的函数.这称为currying.
ljs*_*ljs 46
Currying是一种可以应用于函数的转换,允许它们比以前少一个参数.
例如,在F#中你可以定义一个函数: -
let f x y z = x + y + z
Run Code Online (Sandbox Code Playgroud)
这里函数f取参数x,y和z并将它们加在一起,这样:
f 1 2 3
Run Code Online (Sandbox Code Playgroud)
退货6.
根据我们的定义,我们可以为f定义咖喱函数: -
let curry f = fun x -> f x
Run Code Online (Sandbox Code Playgroud)
其中'fun x - > fx'是一个lambda函数,与C#中的x => f(x)等效.此函数输入您希望curry的函数并返回一个函数,该函数接受一个参数并返回指定的函数,并将第一个参数设置为input参数.
使用我们之前的例子,我们可以获得f的咖喱: -
let curryf = curry f
Run Code Online (Sandbox Code Playgroud)
然后我们可以做以下事情: -
let f1 = curryf 1
Run Code Online (Sandbox Code Playgroud)
这为我们提供了函数f1,它与f1 yz = 1 + y + z等效.这意味着我们可以做到以下几点: -
f1 2 3
Run Code Online (Sandbox Code Playgroud)
哪个返回6.
这个过程经常与"部分功能应用"混淆,后者可以这样定义: -
let papply f x = f x
Run Code Online (Sandbox Code Playgroud)
虽然我们可以将它扩展到多个参数,即: -
let papply2 f x y = f x y
let papply3 f x y z = f x y z
etc.
Run Code Online (Sandbox Code Playgroud)
部分应用程序将获取函数和参数并返回需要一个或多个参数的函数,并且前两个示例show直接在标准F#函数定义中实现,因此我们可以实现以前的结果: -
let f1 = f 1
f1 2 3
Run Code Online (Sandbox Code Playgroud)
这将返回6的结果.
结论:-
currying和部分功能应用之间的区别在于: -
Currying接受一个函数并提供一个接受单个参数的新函数,并返回指定函数,并将其第一个参数设置为该参数.这允许我们将具有多个参数的函数表示为一系列单个参数函数.例:-
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
Run Code Online (Sandbox Code Playgroud)
部分函数应用程序更直接 - 它接受一个函数和一个或多个参数,并返回一个函数,其中前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
Run Code Online (Sandbox Code Playgroud)
Adz*_*dzz 39
它可以是一种使用函数来创建其他函数的方法.
在javascript中:
let add = function(x){
return function(y){
return x + y
};
};
Run Code Online (Sandbox Code Playgroud)
允许我们像这样称呼它:
let addTen = add(10);
Run Code Online (Sandbox Code Playgroud)
当这个运行时,10传入as x;
let add = function(10){
return function(y){
return 10 + y
};
};
Run Code Online (Sandbox Code Playgroud)
这意味着我们返回此功能:
function(y) { return 10 + y };
Run Code Online (Sandbox Code Playgroud)
所以当你打电话
addTen();
Run Code Online (Sandbox Code Playgroud)
你真打电话:
function(y) { return 10 + y };
Run Code Online (Sandbox Code Playgroud)
所以,如果你这样做:
addTen(4)
Run Code Online (Sandbox Code Playgroud)
它是一样的:
function(4) { return 10 + 4} // 14
Run Code Online (Sandbox Code Playgroud)
因此,我们addTen()总是将10加入到我们传入的任何内容中.我们可以以相同的方式创建类似的函数:
let addTwo = add(2) // addTwo(); will add two to whatever you pass in
let addSeventy = add(70) // ... and so on...
Run Code Online (Sandbox Code Playgroud)
Jon*_*rop 27
curried函数是几个重写的参数的函数,它接受第一个参数并返回一个接受第二个参数的函数,依此类推.这允许多个参数的函数部分应用它们的一些初始参数.
这是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..."
Run Code Online (Sandbox Code Playgroud)
(只需通过+使用连接,以避免分散非Python程序员的注意力.)
编辑添加:
请参阅http://docs.python.org/library/functools.html?highlight=partial#functools.partial,它还以Python实现此方式的方式显示了部分对象与函数的区别.
这是通用的示例,也是带有 n 的函数柯里化的最短版本。参数。
const add = a => b => b ? add(a + b) : a;
Run Code Online (Sandbox Code Playgroud)
const add = a => b => b ? add(a + b) : a;
Run Code Online (Sandbox Code Playgroud)
如果你明白partial你就成功了。的想法partial是将参数预应用于函数并返回一个只需要剩余参数的新函数。当这个新函数被调用时,它包括预加载的参数以及提供给它的任何参数。
在 Clojure 中+是一个函数,但让事情变得非常清楚:
(defn add [a b] (+ a b))
Run Code Online (Sandbox Code Playgroud)
您可能知道该inc函数只是将它传递的任何数字加 1。
(inc 7) # => 8
Run Code Online (Sandbox Code Playgroud)
让我们自己使用partial:
(def inc (partial add 1))
Run Code Online (Sandbox Code Playgroud)
这里我们返回另一个函数,该函数将 1 加载到 的第一个参数中add。由于add需要两个参数,新inc函数只需要b参数——不像以前那样需要 2 个参数,因为 1 已经被部分应用。因此partial,它是一个工具,可以从中创建具有预先提供的默认值的新函数。这就是为什么在函数式语言中,函数通常将参数从一般排序到特定。这使得重用这些函数来构造其他函数变得更加容易。
现在想象一下,如果语言足够聪明,可以内省地理解add需要两个论点。当我们向它传递一个参数时,而不是犹豫不决,如果函数部分应用了我们代表我们传递的参数,我们理解我们可能打算稍后提供另一个参数怎么办?然后我们可以在inc不显式使用的情况下进行定义partial。
(def inc (add 1)) #partial is implied
Run Code Online (Sandbox Code Playgroud)
这是某些语言的行为方式。当人们希望将函数组合成更大的转换时,它特别有用。这将导致一个换能器。
小智 5
Currying is translating a function from callable as f(a, b, c) into callable as f(a)(b)(c).
Otherwise currying is when you break down a function that takes multiple arguments into a series of functions that take part of the arguments.
Literally, currying is a transformation of functions: from one way of calling into another. In JavaScript, we usually make a wrapper to keep the original function.
Currying doesn’t call a function. It just transforms it.
Let’s make curry function that performs currying for two-argument functions. In other words, curry(f) for two-argument f(a, b) translates it into 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
Run Code Online (Sandbox Code Playgroud)
As you can see, the implementation is a series of wrappers.
curry(func) is a wrapper function(a).sum(1), the argument is saved in the Lexical Environment, and a new wrapper is returned function(b).sum(1)(2) finally calls function(b) providing 2, and it passes the call to the original multi-argument sum.小智 5
柯里化是 Java Script 的高阶函数之一。
柯里化是一个包含多个参数的函数,它被重写为接受第一个参数并返回一个函数,该函数依次使用剩余的参数并返回值。
使困惑?
看个例子,
function add(a,b)
{
return a+b;
}
add(5,6);
Run Code Online (Sandbox Code Playgroud)
这类似于下面的柯里化函数,
function add(a)
{
return function(b){
return a+b;
}
}
var curryAdd = add(5);
curryAdd(6);
Run Code Online (Sandbox Code Playgroud)
那么这段代码是什么意思呢?
现在再次阅读定义,
柯里化是一个包含许多参数的函数,它被重写为接受第一个参数并返回一个函数,该函数依次使用剩余的参数并返回值。
还是,迷茫?让我深入解释一下!
当你调用这个函数时,
var curryAdd = add(5);
Run Code Online (Sandbox Code Playgroud)
它会返回一个这样的函数,
curryAdd=function(y){return 5+y;}
Run Code Online (Sandbox Code Playgroud)
因此,这称为高阶函数。意思是,依次调用一个函数返回另一个函数是高阶函数的精确定义。这是传说中 Java Script 的最大优势。所以回到咖喱,
这一行将第二个参数传递给 curryAdd 函数。
curryAdd(6);
Run Code Online (Sandbox Code Playgroud)
结果,
curryAdd=function(6){return 5+6;}
// Which results in 11
Run Code Online (Sandbox Code Playgroud)
希望你在这里理解柯里化的用法。所以,来到优势,
为什么要咖喱?
它利用了代码的可重用性。更少的代码,更少的错误。你可能会问怎么是少代码?
我可以用 ECMA 脚本 6 新特性箭头函数来证明这一点。
是的!ECMA 6,为我们提供了一个叫做箭头函数的奇妙特性,
function add(a)
{
return function(b){
return a+b;
}
}
Run Code Online (Sandbox Code Playgroud)
借助箭头函数,我们可以将上面的函数写成如下,
x=>y=>x+y
Run Code Online (Sandbox Code Playgroud)
酷吧?
所以,更少的代码和更少的错误!!
借助这些高阶函数,可以轻松开发出无错误代码。
我挑战你!
希望,你明白什么是柯里化。如果您需要任何说明,请随时在此处发表评论。
谢谢,祝你有美好的一天!
这是一个有意义的真实单词示例:
你去ATM取钱。您刷卡,输入密码并进行选择,然后按回车键提交请求旁边的“金额”。
这是取款的正常功能。
const withdraw=(cardInfo,pinNumber,request){
// process it
return request.amount
}
Run Code Online (Sandbox Code Playgroud)
在这个实现中,函数期望我们一次输入所有参数。我们要刷卡,输入密码并发出请求,然后函数就会运行。如果这些步骤中的任何一个有问题,您会在输入所有参数后发现。使用柯里化函数,我们将创建更高数量的、纯粹的和简单的函数。纯函数将帮助我们轻松调试代码。
这是带有咖喱函数的 Atm:
const withdraw=(cardInfo)=>(pinNumber)=>(request)=>request.amount
Run Code Online (Sandbox Code Playgroud)
ATM 将卡作为输入并返回一个需要 pinNumber 的函数,该函数返回一个接受请求对象的函数,成功处理后,您将获得请求的金额。每一步,如果你有一个错误,你会很容易地预测哪里出了问题。假设您输入卡并出错,您知道它与卡或机器有关,但与密码无关。或者,如果您输入了 PIN 码但没有被接受,您就知道您输入了错误的 PIN 码。您将轻松调试错误。
此外,这里的每个函数都是可重用的,因此您可以在项目的不同部分使用相同的函数。