JavaScript curry:实际应用有哪些?

发布于 2024-07-06 12:46:54 字数 1774 浏览 7 评论 0原文

我想我还没有学会咖喱。 我了解它的作用以及如何做。 我只是想不出我会使用它的情况。

你在 JavaScript 中的什么地方使用柯里化(或者主要的库在哪里使用它)? 欢迎 DOM 操作或一般应用程序开发示例。

其中一个答案提到了动画。 像 slideUpfadeIn 这样的函数将一个元素作为参数,通常是一个柯里化函数,返回带有默认内置“动画函数”的高阶函数。 为什么这比仅应用具有某些默认值的上层函数更好?

使用它有什么缺点吗?

根据要求,这里有一些关于 JavaScript 柯里化的好资源:

我会在评论中出现更多内容时添加它们。


因此,根据答案,柯里化和部分应用通常是方便的技术。

如果您经常通过使用相同的配置调用高级函数来“精炼”它,则可以柯里化(或使用 Resig 的部分)高级函数来创建简单、简洁的辅助方法。

I don’t think I’ve grokked currying yet. I understand what it does, and how to do it. I just can’t think of a situation I would use it.

Where are you using currying in JavaScript (or where are the main libraries using it)? DOM manipulation or general application development examples welcome.

One of the answers mentions animation. Functions like slideUp, fadeIn take an element as an arguments and are normally a curried function returning the high order function with the default “animation function” built-in. Why is that better than just applying the higher-up function with some defaults?

Are there any drawbacks to using it?

As requested here are some good resources on JavaScript currying:

I’ll add more as they crop up in the comments.


So, according to the answers, currying and partial application in general are convenience techniques.

If you are frequently “refining” a high-level function by calling it with same configuration, you can curry (or use Resig’s partial) the higher-level function to create simple, concise helper methods.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

时光瘦了 2024-07-13 12:46:54

这是在使用闭包的 JavaScript 中进行柯里化的有趣且实用的用法

函数转换器(toUnit,因子,偏移量,输入){ 
      偏移量=偏移量||   0; 
      return [((偏移量+输入) * 因子).toFixed(2), toUnit].join(" "); 
  } 

  var MilesToKm = converter.curry('km', 1.60936, undefined); 
  var磅ToKg =转换器.curry('kg',0.45460,未定义); 
  var farenheitToCelsius = converter.curry('摄氏度', 0.5556, -32); 

  英里到公里(10);   // 返回“16.09 公里” 
  磅换算为公斤(2.5);   // 返回“1.14 千克” 
  华氏度转摄氏度(98);   // 返回“36.67 摄氏度” 
  

这依赖于 Functioncurry 扩展,尽管您可以看到它只使用 apply (没什么太花哨的):

Function.prototype.curry = function() { 
      if (arguments.length < 1) { 
          返回这个;   //没什么可柯里化的 - 返回函数 
      } 
      var __method = this; 
      var args = toArray(参数); 
      返回函数(){ 
          return __method.apply(this, args.concat([].slice.apply(null,arguments))); 
      } 
  } 
  

Here's an interesting AND practical use of currying in JavaScript that uses closures:

function converter(toUnit, factor, offset, input) {
    offset = offset || 0;
    return [((offset + input) * factor).toFixed(2), toUnit].join(" ");
}

var milesToKm = converter.curry('km', 1.60936, undefined);
var poundsToKg = converter.curry('kg', 0.45460, undefined);
var farenheitToCelsius = converter.curry('degrees C', 0.5556, -32);

milesToKm(10);            // returns "16.09 km"
poundsToKg(2.5);          // returns "1.14 kg"
farenheitToCelsius(98);   // returns "36.67 degrees C"

This relies on a curry extension of Function, although as you can see it only uses apply (nothing too fancy):

Function.prototype.curry = function() {
    if (arguments.length < 1) {
        return this; //nothing to curry with - return function
    }
    var __method = this;
    var args = toArray(arguments);
    return function() {
        return __method.apply(this, args.concat([].slice.apply(null, arguments)));
    }
}
小嗷兮 2024-07-13 12:46:54

@Hank Gay

回应 EmbiggensTheMind 的评论:

我想不出 柯里化 的实例 -本身——在 JavaScript 中很有用; 它是一种将具有多个参数的函数调用转换为每次调用一个参数的函数调用链的技术,但 JavaScript 支持在单个函数调用中使用多个参数。

不过,在 JavaScript 中(我假设大多数其他实际语言(不是 lambda 演算)),它通常与部分应用程序相关。 John Resig 解释得更好,但要点是有一些将应用于两个或多个参数的逻辑,并且您只知道其中某些参数的值。

您可以使用部分应用程序/柯里化来修复这些已知值并返回一个仅接受未知数的函数,以便稍后在您实际拥有希望传递的值时调用。 当您使用除一个之外的所有相同值一遍又一遍地调用相同的 JavaScript 内置函数时,这提供了一种避免重复的好方法。 盗用约翰的例子:

String.prototype.csv = String.prototype.split.partial(/,\s*/);
var results = "John, Resig, Boston".csv();
alert( (results[1] == "Resig") + " The text values were split properly" );

@Hank Gay

In response to EmbiggensTheMind's comment:

I can't think of an instance where currying—by itself—is useful in JavaScript; it is a technique for converting function calls with multiple arguments into chains of function calls with a single argument for each call, but JavaScript supports multiple arguments in a single function call.

In JavaScript—and I assume most other actual languages (not lambda calculus)—it is commonly associated with partial application, though. John Resig explains it better, but the gist is that have some logic that will be applied to two or more arguments, and you only know the value(s) for some of those arguments.

You can use partial application/currying to fix those known values and return a function that only accepts the unknowns, to be invoked later when you actually have the values you wish to pass. This provides a nifty way to avoid repeating yourself when you would have been calling the same JavaScript built-ins over and over with all the same values but one. To steal John's example:

String.prototype.csv = String.prototype.split.partial(/,\s*/);
var results = "John, Resig, Boston".csv();
alert( (results[1] == "Resig") + " The text values were split properly" );
oО清风挽发oО 2024-07-13 12:46:54

同意 Hank Gay 的观点 - 它在某些真正的函数式编程语言中非常有用 - 因为它是必要的一部分。 例如,在 Haskell 中,你根本无法将多个参数传递给一个函数 - 在纯函数式编程中你无法做到这一点。 您一次获取一个参数并构建您的函数。 在 JavaScript 中,它根本没有必要,尽管有像“转换器”这样的人为示例。 这是相同的转换器代码,不需要柯里化:

var converter = function(ratio, symbol, input) {
    return (input*ratio).toFixed(2) + " " + symbol;
}

var kilosToPoundsRatio = 2.2;
var litersToUKPintsRatio = 1.75;
var litersToUSPintsRatio = 1.98;
var milesToKilometersRatio = 1.62;

converter(kilosToPoundsRatio, "lbs", 4); //8.80 lbs
converter(litersToUKPintsRatio, "imperial pints", 2.4); //4.20 imperial pints
converter(litersToUSPintsRatio, "US pints", 2.4); //4.75 US pints
converter(milesToKilometersRatio, "km", 34); //55.08 km

我非常希望道格拉斯·克罗克福德 (Douglas Crockford) 在“JavaScript:优秀部分”中提及柯里化的历史和实际使用,而不是他即兴的评论。 读完这篇文章后的很长一段时间里,我都感到困惑,直到我学习函数式编程并意识到这就是它的来源。

经过更多思考,我认为 JavaScript 中的柯里化有一个有效的用例:如果您尝试使用 JavaScript 使用纯函数式编程技术进行编写。 不过,这似乎是一个罕见的用例。

Agreeing with Hank Gay - It's extremely useful in certain true functional programming languages - because it's a necessary part. For example, in Haskell you simply cannot take multiple parameters to a function - you cannot do that in pure functional programming. You take one param at a time and build up your function. In JavaScript it's simply unnecessary, despite contrived examples like "converter". Here's that same converter code, without the need for currying:

var converter = function(ratio, symbol, input) {
    return (input*ratio).toFixed(2) + " " + symbol;
}

var kilosToPoundsRatio = 2.2;
var litersToUKPintsRatio = 1.75;
var litersToUSPintsRatio = 1.98;
var milesToKilometersRatio = 1.62;

converter(kilosToPoundsRatio, "lbs", 4); //8.80 lbs
converter(litersToUKPintsRatio, "imperial pints", 2.4); //4.20 imperial pints
converter(litersToUSPintsRatio, "US pints", 2.4); //4.75 US pints
converter(milesToKilometersRatio, "km", 34); //55.08 km

I badly wish Douglas Crockford, in "JavaScript: The Good Parts", had given some mention of the history and actual use of currying rather than his offhanded remarks. For the longest time after reading that, I was boggled, until I was studying Functional programming and realized that's where it came from.

After some more thinking, I posit there is one valid use case for currying in JavaScript: if you are trying to write using pure functional programming techniques using JavaScript. Seems like a rare use case though.

征﹌骨岁月お 2024-07-13 12:46:54

我发现类似于 python 的 functools.partial 的函数在 JavaScript 中更有用:

function partial(fn) {
  return partialWithScope.apply(this,
    Array.prototype.concat.apply([fn, this],
      Array.prototype.slice.call(arguments, 1)));
}

function partialWithScope(fn, scope) {
  var args = Array.prototype.slice.call(arguments, 2);
  return function() {
    return fn.apply(scope, Array.prototype.concat.apply(args, arguments));
  };
}

为什么要使用它? 想要使用 this 的常见情况是当您想要将函数中的 this 绑定到一个值时:

var callback = partialWithScope(Object.function, obj);

现在,当调用回调时,this 指向 obj。 这在事件情况下很有用,或者可以节省一些空间,因为它通常会使代码更短。

柯里化与部分类似,区别在于柯里化返回的函数只接受一个参数(据我所知)。

I found functions that resemble python's functools.partial more useful in JavaScript:

function partial(fn) {
  return partialWithScope.apply(this,
    Array.prototype.concat.apply([fn, this],
      Array.prototype.slice.call(arguments, 1)));
}

function partialWithScope(fn, scope) {
  var args = Array.prototype.slice.call(arguments, 2);
  return function() {
    return fn.apply(scope, Array.prototype.concat.apply(args, arguments));
  };
}

Why would you want to use it? A common situation where you want to use this is when you want to bind this in a function to a value:

var callback = partialWithScope(Object.function, obj);

Now when callback is called, this points to obj. This is useful in event situations or to save some space because it usually makes code shorter.

Currying is similar to partial with the difference that the function the currying returns just accepts one argument (as far as I understand that).

怎会甘心 2024-07-13 12:46:54

考虑filter 函数。 并且您想为其编写一个回调。

let x = [1,2,3,4,5,6,7,11,12,14,15];
let results = x.filter(callback);

假设只想输出偶数,所以:

let callback = x => x % 2 === 0;

现在假设我们想要实现我们的回调,这样
根据场景,它会输出高于某个阈值的偶数(例如
数量应该是可配置的)。

我们不能轻易地将这样的阈值数字作为回调函数的参数,因为过滤器调用回调并默认向其传递数组元素和索引。

你会如何实施这个?

这是柯里化的一个很好的用例:

let x = [1,2,3,4,5,6,7,11,12,14,15];
let callback = (threshold) => (x) => (x % 2==0 && x > threshold);

let results1 = x.filter(callback(5)); // Even numbers higher than 5
let results2 = x.filter(callback(10)); // Even numbers higher than 10

console.log(results1,results2);

Consider filter function. And you want to write a callback for it.

let x = [1,2,3,4,5,6,7,11,12,14,15];
let results = x.filter(callback);

Assume want to output only even numbers, so:

let callback = x => x % 2 === 0;

Now imagine we want to implement our callback such that
depending on scenario it outputs even numbers which are above some threshold number (such
number should be configurable).

We can't easily make such threshold number a parameter to callback function, because filter invokes callback and by default passes it array elements and index.

How would you implement this?

This is a good use case for currying:

let x = [1,2,3,4,5,6,7,11,12,14,15];
let callback = (threshold) => (x) => (x % 2==0 && x > threshold);

let results1 = x.filter(callback(5)); // Even numbers higher than 5
let results2 = x.filter(callback(10)); // Even numbers higher than 10

console.log(results1,results2);

篱下浅笙歌 2024-07-13 12:46:54

我知道它的旧线程,但我必须展示如何在 javascript 库中使用它:

我将使用 lodash.js 库来具体描述这些概念。

示例:

var fn = function(a,b,c){ 
return a+b+c+(this.greet || ‘'); 
}

部分应用:

var partialFnA = _.partial(fn, 1,3);

柯里化:

var curriedFn = _.curry(fn);

绑定:

var boundFn = _.bind(fn,object,1,3 );//object= {greet: ’!'}

用法:

curriedFn(1)(3)(5); // gives 9 
or 
curriedFn(1,3)(5); // gives 9 
or 
curriedFn(1)(_,3)(2); //gives 9


partialFnA(5); //gives 9

boundFn(5); //gives 9!

差异:

柯里化后,我们得到一个没有预先绑定参数的新函数。

在部分应用之后,我们得到一个与一些预先绑定的参数绑定的函数。

在绑定中,我们可以绑定一个上下文,该上下文将用于替换“this”,如果没有绑定,则任何函数的默认值都将是窗口范围。

建议:没有必要重新发明轮子。 部分应用/绑定/柯里化非常相关。 您可以看到上面的区别。 在任何地方使用这个含义,人们都会认识到你在做什么,而不会出现理解问题,而且你将不得不使用更少的代码。

I know its old thread but I will have to show how this is being used in javascript libraries:

I will use lodash.js library to describe these concepts concretely.

Example:

var fn = function(a,b,c){ 
return a+b+c+(this.greet || ‘'); 
}

Partial Application:

var partialFnA = _.partial(fn, 1,3);

Currying:

var curriedFn = _.curry(fn);

Binding:

var boundFn = _.bind(fn,object,1,3 );//object= {greet: ’!'}

usage:

curriedFn(1)(3)(5); // gives 9 
or 
curriedFn(1,3)(5); // gives 9 
or 
curriedFn(1)(_,3)(2); //gives 9


partialFnA(5); //gives 9

boundFn(5); //gives 9!

difference:

after currying we get a new function with no parameters pre bound.

after partial application we get a function which is bound with some parameters prebound.

in binding we can bind a context which will be used to replace ‘this’, if not bound default of any function will be window scope.

Advise: There is no need to reinvent the wheel. Partial application/binding/currying are very much related. You can see the difference above. Use this meaning anywhere and people will recognise what you are doing without issues in understanding plus you will have to use less code.

心病无药医 2024-07-13 12:46:54

它不是什么魔法或什么...只是匿名函数的一个令人愉快的简写。

partial(alert, "FOO!") 等价于 function(){alert("FOO!");}

partial(Math.max, 0) 对应于 function(x){return Math.max(0, x);}

对partial (MochiKit 术语。我认为其他一些库为函数提供了一个 .curry 方法,它做同样的事情)看起来比匿名函数稍微好一点,噪音也少。

It's no magic or anything... just a pleasant shorthand for anonymous functions.

partial(alert, "FOO!") is equivalent to function(){alert("FOO!");}

partial(Math.max, 0) corresponds to function(x){return Math.max(0, x);}

The calls to partial (MochiKit terminology. I think some other libraries give functions a .curry method which does the same thing) look slightly nicer and less noisy than the anonymous functions.

海螺姑娘 2024-07-13 12:46:54

至于使用它的库,总是有功能

在JS中什么时候有用? 可能在其他现代语言中它也很有用,但我唯一能看到自己使用它的是与部分应用程序结合使用。

As for libraries using it, there's always Functional.

When is it useful in JS? Probably the same times it is useful in other modern languages, but the only time I can see myself using it is in conjunction with partial application.

缺⑴份安定 2024-07-13 12:46:54

我想说,很可能,JS 中的所有动画库都在使用柯里化。 不必为每次调用传递一组受影响的元素和一个函数(描述元素的行为方式)到确保所有计时内容的高阶函数,客户通常更容易发布,因为公共 API 一些像“slideUp”、“fadeIn”这样的函数只接受元素作为参数,并且只是一些柯里化函数,返回带有默认内置“动画函数”的高阶函数。

I would say that, most probably, all the animation library in JS are using currying. Rather than having to pass for each call a set of impacted elements and a function, describing how the element should behave, to a higher order function that will ensure all the timing stuff, its generally easier for the customer to release, as public API some function like "slideUp", "fadeIn" that takes only elements as arguments, and that are just some curried function returning the high order function with the default "animation function" built-in.

み零 2024-07-13 12:46:54

这是一个例子。

我正在使用 JQuery 检测大量字段,这样我就可以看到用户在做什么。 代码如下所示:(

$('#foo').focus(trackActivity);
$('#foo').blur(trackActivity);
$('#bar').focus(trackActivity);
$('#bar').blur(trackActivity);

对于非 JQuery 用户,我是说,每当几个字段获得或失去焦点时,我都希望调用 trackActivity() 函数。我也可以使用匿名函数,但我必须将其复制 4 次,所以我将其取出并命名。)

现在事实证明,其中一个字段需要以不同的方式处理。 我希望能够在其中一个调用中传递一个参数,以传递到我们的跟踪基础设施。 通过咖喱,我可以。

Here's an example.

I'm instrumenting a bunch of fields with JQuery so I can see what users are up to. The code looks like this:

$('#foo').focus(trackActivity);
$('#foo').blur(trackActivity);
$('#bar').focus(trackActivity);
$('#bar').blur(trackActivity);

(For non-JQuery users, I'm saying that any time a couple of fields get or lose focus, I want the trackActivity() function to be called. I could also use an anonymous function, but I'd have to duplicate it 4 times, so I pulled it out and named it.)

Now it turns out that one of those fields needs to be handled differently. I'd like to be able to pass a parameter in on one of those calls to be passed along to our tracking infrastructure. With currying, I can.

望她远 2024-07-13 12:46:54

JavaScript 函数在其他函数式语言中被称为 lamda。 它可用于根据其他开发人员的简单输入来组合新的 api(更强大或更复杂的功能)。 咖喱只是技术之一。 您可以使用它创建一个简化的 api 来调用复杂的 api。 如果您是使用简化API的开发者(例如您使用jQuery进行简单操作),则不需要使用curry。 但如果你想创建简化的 api,Curry 是你的朋友。 你必须编写一个 javascript 框架(如 jQuery、mootools)或库,然后你才能体会到它的强大功能。 我在 http://blog.semanticsworks.com 编写了一个增强的 curry 函数/2011/03/enhanced-curry-method.html 。 您不需要使用 curry 方法来进行柯里化,它只是有助于进行柯里化,但您始终可以通过编写函数 A(){} 来返回另一个函数 B(){} 来手动完成此操作。 为了让它更有趣,使用函数 B() 返回另一个函数 C()。

JavaScript functions is called lamda in other functional language. It can be used to compose a new api (more powerful or complext function) to based on another developer's simple input. Curry is just one of the techniques. You can use it to create a simplified api to call a complex api. If you are the develper who use the simplified api (for example you use jQuery to do simple manipulation), you don't need to use curry. But if you want to create the simplified api, curry is your friend. You have to write a javascript framework (like jQuery, mootools) or library, then you can appreciate its power. I wrote a enhanced curry function, at http://blog.semanticsworks.com/2011/03/enhanced-curry-method.html . You don't need to the curry method to do currying, it just help to do currying, but you can always do it manually by writing a function A(){} to return another function B(){}. To make it more interesting, use function B() to return another function C().

爱已欠费 2024-07-13 12:46:54

我同意,有时您希望通过创建一个伪函数来开始工作,该伪函数始终填充第一个参数的值。幸运的是,我遇到了一个名为 jPaq 的全新 JavaScript 库(http://jpaq.org/)提供了此功能。 该库的最大优点是您可以下载自己的构建版本,其中仅包含您需要的代码。

I agree that at times you would like to get the ball rolling by creating a pseudo-function that will always have the value of the first argument filled in. Fortunately, I came across a brand new JavaScript library called jPaq (http://jpaq.org/) which provides this functionality. The best thing about the library is the fact that you can download your own build which contains only the code that you will need.

影子是时光的心 2024-07-13 12:46:54

只是想为Functional.js 添加一些资源:

解释一些应用程序的讲座/会议
http://www.youtube.com/watch?v=HAcN3JyQoyY

更新了Functional.js图书馆:
https://github.com/loop-recur/FunctionalJS
一些好帮手(抱歉,新来的,没有声誉:p):
/loop-recur/PreludeJS

我最近经常使用这个库来减少 js IRC 客户端帮助程序库中的重复。 这是很棒的东西——确实有助于清理和简化代码。

此外,如果性能成为一个问题(但这个库非常轻),那么很容易使用本机函数重写。

Just wanted to add some resources for Functional.js:

Lecture/conference explaining some applications
http://www.youtube.com/watch?v=HAcN3JyQoyY

Updated Functional.js library:
https://github.com/loop-recur/FunctionalJS
Some nice helpers (sorry new here, no reputation :p):
/loop-recur/PreludeJS

I've been using this library a lot recently to reduce the repetition in an js IRC clients helper library. It's great stuff - really helps clean up and simplify code.

In addition, if performance becomes an issue (but this lib is pretty light), it's easy to just rewrite using a native function.

不美如何 2024-07-13 12:46:54

您可以使用本机绑定来实现快速的一行解决方案

function clampAngle(min, max, angle) {
    var result, delta;
    delta = max - min;
    result = (angle - min) % delta;
    if (result < 0) {
        result += delta;
    }
    return min + result;
};

var clamp0To360 = clampAngle.bind(null, 0, 360);

console.log(clamp0To360(405)) // 45

You can use native bind for quick, one line solution

function clampAngle(min, max, angle) {
    var result, delta;
    delta = max - min;
    result = (angle - min) % delta;
    if (result < 0) {
        result += delta;
    }
    return min + result;
};

var clamp0To360 = clampAngle.bind(null, 0, 360);

console.log(clamp0To360(405)) // 45

许一世地老天荒 2024-07-13 12:46:54

另一个尝试,来自于承诺。

(免责声明:JS 菜鸟,来自 Python 世界。即使在那里,柯里化 也没有被经常使用,但它有时会派上用场。所以我抄袭了柯里化函数 - 请参阅链接)

首先,我从 ajax 调用开始。 我在成功时需要进行一些特定的处理,但在失败时,我只想向用户提供反馈:调用某事导致某些错误。 在我的实际代码中,我在引导面板中显示错误反馈,但我只是在此处使用日志记录。

我修改了我的实时网址以使其失败。

function ajax_batch(e){
    var url = $(e.target).data("url");

    //induce error
    url = "x" + url;

    var promise_details = $.ajax(
        url,
        {
            headers: { Accept : "application/json" },
            // accepts : "application/json",
            beforeSend: function (request) {
                if (!this.crossDomain) {
                    request.setRequestHeader("X-CSRFToken", csrf_token);
                }
        },
        dataType : "json",
        type : "POST"}
    );
    promise_details.then(notify_batch_success, fail_status_specific_to_batch);
}

现在,为了告诉用户批次失败,我需要在错误处理程序中写入该信息,因为它得到的只是来自服务器的响应。

我仍然只有在编码时可用的信息 - 就我而言,我有许多可能的批次,但我不知道哪一个批次在解析有关失败网址的服务器响应时失败了。

function fail_status_specific_to_batch(d){
    console.log("bad batch run, dude");
    console.log("response.status:" + d.status);
}

我们开始做吧。 控制台输出为:

控制台:

错误的批处理运行,伙计
utility.js(第 109 行)
response.status:404

现在,让我们稍微改变一下,并使用一个可重用的通用故障处理程序,同时也是一个在运行时使用已知代码时调用进行柯里化的处理程序上下文和事件中可用的运行时信息。

    ... rest is as before...
    var target = $(e.target).text();
    var context = {"user_msg": "bad batch run, dude.  you were calling :" + target};
    var contexted_fail_notification = curry(generic_fail, context); 

    promise_details.then(notify_batch_success, contexted_fail_notification);
}

function generic_fail(context, d){
    console.log(context);
    console.log("response.status:" + d.status);
}

function curry(fn) {
     var slice = Array.prototype.slice,
        stored_args = slice.call(arguments, 1);
     return function () {
        var new_args = slice.call(arguments),
              args = stored_args.concat(new_args);
        return fn.apply(null, args);
     };
}

console:

Object { user_msg="糟糕的批处理运行,伙计。你正在调用:现在运行 ACL"}
utility.js(第 117 行)
响应状态:404
utility.js(第 118 行)

更一般地说,考虑到回调在 JS 中的广泛使用,柯里化似乎是一个非常有用的工具。

https://javascriptweblog.wordpress.com/2010/ 04/05/咖喱烹饪更美味的功能/
http://www.drdobbs .com/open-source/currying-and-partial-functions-in-javasc/231001821?pgno=2

Another stab at it, from working with promises.

(Disclaimer: JS noob, coming from the Python world. Even there, currying is not used all that much, but it can come in handy on occasion. So I cribbed the currying function - see links)

First, I am starting with an ajax call. I have some specific processing to do on success, but on failure, I just want to give the user the feedback that calling something resulted in some error. In my actual code, I display the error feedback in a bootstrap panel, but am just using logging here.

I've modified my live url to make this fail.

function ajax_batch(e){
    var url = $(e.target).data("url");

    //induce error
    url = "x" + url;

    var promise_details = $.ajax(
        url,
        {
            headers: { Accept : "application/json" },
            // accepts : "application/json",
            beforeSend: function (request) {
                if (!this.crossDomain) {
                    request.setRequestHeader("X-CSRFToken", csrf_token);
                }
        },
        dataType : "json",
        type : "POST"}
    );
    promise_details.then(notify_batch_success, fail_status_specific_to_batch);
}

Now, here in order to tell the user that a batch failed, I need to write that info in the error handler, because all it is getting is a response from the server.

I still only have the info available at coding time - in my case I have a number of possible batches, but I don't know which one has failed w.o. parsing the server response about the failed url.

function fail_status_specific_to_batch(d){
    console.log("bad batch run, dude");
    console.log("response.status:" + d.status);
}

Let's do it. Console output is:

console:

bad batch run, dude
utility.js (line 109)
response.status:404

Now, let's change things a bit and use a reusable generic failure handler, but also one that is curried at runtime with both the known-at-code-time calling context and the run-time info available from event.

    ... rest is as before...
    var target = $(e.target).text();
    var context = {"user_msg": "bad batch run, dude.  you were calling :" + target};
    var contexted_fail_notification = curry(generic_fail, context); 

    promise_details.then(notify_batch_success, contexted_fail_notification);
}

function generic_fail(context, d){
    console.log(context);
    console.log("response.status:" + d.status);
}

function curry(fn) {
     var slice = Array.prototype.slice,
        stored_args = slice.call(arguments, 1);
     return function () {
        var new_args = slice.call(arguments),
              args = stored_args.concat(new_args);
        return fn.apply(null, args);
     };
}

console:

Object { user_msg="bad batch run, dude. you were calling :Run ACL now"}
utility.js (line 117)
response.status:404
utility.js (line 118)

More generally, given how widespread callback usage is in JS, currying seems like a quite useful tool to have.

https://javascriptweblog.wordpress.com/2010/04/05/curry-cooking-up-tastier-functions/
http://www.drdobbs.com/open-source/currying-and-partial-functions-in-javasc/231001821?pgno=2

青瓷清茶倾城歌 2024-07-13 12:46:54

我在 https://softwareengineering.stackexchange 提出了类似的问题。 com/questions/384529/a-real-life-example-of-using-curry-function

但只有在我使用 ramda我终于体会到咖喱的用处了。 因此,我认为,如果我们需要将函数链接在一起来一次一步处理某些输入数据,例如文章 偏向 Curry,按照“函数第一,数据最后”的方式使用 curry,代码确实看起来很干净!

I asked a similar question at https://softwareengineering.stackexchange.com/questions/384529/a-real-life-example-of-using-curry-function

But only after I use ramda do I finally appreciate the usefulness of curry. So I will argue that if we need to chain functions together to process some input data one step a time, e.g. the promise chain example in the article Favoring Curry, using curry by "function first,data last", the code does look clean!

如痴如狂 2024-07-13 12:46:54

这里有一个目前正在使用柯里化的实际例子。
https://www.joshwcomeau.com/react/demystifying-styled-components/< /a>

基本上,他正在创建一个穷人风格的组件,并在为其创建新样式时使用柯里化来“预加载”标签的名称。

Here you have a practical example of were currying is being used at the moment.
https://www.joshwcomeau.com/react/demystifying-styled-components/

Basically he is creating a poor man styled components and uses currying to "preload" the name of the tag when creating a new style for it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文