我在一些文章和博客中看到了curry函数的引用,但我找不到一个好的解释(或者至少一个有意义的解释!)
当前回答
这个线程中的大多数例子都是虚构的(添加数字)。这些对于说明这个概念很有用,但当你在应用程序中实际使用咖喱时,它们就没有意义了。
下面是一个来自React (JavaScript用户界面库)的实例。这里的curry说明了闭包属性。
与大多数用户界面库中的典型情况一样,当用户单击按钮时,将调用一个函数来处理该事件。处理程序通常修改应用程序的状态并触发接口重新呈现。
项目列表是常见的用户界面组件。每个项目都可能有一个与之相关的标识符(通常与数据库记录相关)。例如,当用户单击按钮以“喜欢”列表中的某项时,处理程序需要知道单击了哪个按钮。
curry是实现id和处理程序之间绑定的一种方法。在下面的代码中,makeClickHandler是一个函数,它接受一个id,并返回一个在其作用域中包含id的处理程序函数。
内部函数的工作方式在本文中并不重要。但如果你好奇的话,它会在项目数组中搜索,通过id找到一个项目,并增加它的“喜欢”,通过设置状态触发另一次呈现。State在React中是不可变的,所以修改一个值所花费的工作比你想象的要多一些。
您可以将调用curry函数视为“剥离”外部函数以公开准备调用的内部函数。这个新的内部函数是传递给React的onClick的实际处理程序。外部函数用于循环体指定特定内部处理函数范围内的id。
const List = () => { const [items, setItems] = React.useState([ {name: "foo", likes: 0}, {name: "bar", likes: 0}, {name: "baz", likes: 0}, ].map(e => ({...e, id: crypto.randomUUID()}))); // .----------. outer func inner func // | currying | | | // `----------` V V const makeClickHandler = (id) => (event) => { setItems(prev => { const i = prev.findIndex(e => e.id === id); const cpy = {...prev[i]}; cpy.likes++; return [ ...prev.slice(0, i), cpy, ...prev.slice(i + 1) ]; }); }; return ( <ul> {items.map(({name, likes, id}) => <li key={id}> <button onClick={ /* strip off first function layer to get a click handler bound to `id` and pass it to onClick */ makeClickHandler(id) } > {name} ({likes} likes) </button> </li> )} </ul> ); }; ReactDOM.render( <List />, document.querySelector("#root") ); button { font-family: monospace; font-size: 2em; } <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script> <div id="root"></div>
其他回答
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。
“Currying”是一个获取多个参数的函数并将其转换为一系列函数的过程,每个函数接受一个参数并返回一个参数的函数,或者在最终函数的情况下,返回实际结果。
下面是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..."
(只是通过+来使用连接,以避免非python程序员分心。)
编辑添加:
看到http://docs.python.org/library/functools.html?highlight=partial functools.partial, 这也显示了Python实现的部分对象和函数的区别。
Curry可以简化代码。这是使用它的主要原因之一。curry是将一个接受n个参数的函数转换为n个只接受一个参数的函数的过程。
其原理是传递传递函数的参数,使用closure(闭包)属性,将它们存储在另一个函数中并将其作为返回值,这些函数形成一个链,最后的参数被传递进来完成操作。
这样做的好处是可以通过一次处理一个参数来简化参数的处理,也可以提高程序的灵活性和可读性。这也使程序更易于管理。此外,将代码分割成更小的片段将使其易于重用。
例如:
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);
这对于使复杂的代码变得整洁和处理非同步方法等非常有用。
正如所有其他答案一样,咖喱有助于创建部分应用函数。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)
推荐文章
- 使用jQuery改变输入字段的类型
- 在JavaScript中,什么相当于Java的Thread.sleep() ?
- 使用jQuery以像素为整数填充或边距值
- 模式、表和数据库之间的区别是什么?
- 检查是否选择了jQuery选项,如果没有选择默认值
- Next.js React应用中没有定义Window
- 如何重置笑话模拟函数调用计数之前,每次测试
- 如何强制一个功能React组件渲染?
- 在javascript中从平面数组构建树数组
- 将Dropzone.js与其他字段集成到现有的HTML表单中
- 如何在AngularJS中观察路由变化?
- JavaScript DOM删除元素
- 覆盖或覆盖
- 将dd-mm-yyyy字符串转换为日期
- Javascript复选框onChange