Aad*_*hah 1 javascript functional-programming currying apply ecmascript-6
我喜欢ECMAScript 6允许您编写如下的咖喱函数:
var add = x => y => z => x + y + z;
Run Code Online (Sandbox Code Playgroud)
但是,我讨厌我们需要在咖喱函数的每个参数中加上括号:
add(2)(3)(5);
Run Code Online (Sandbox Code Playgroud)
我希望能够一次将咖喱函数应用于多个参数:
add(2, 3, 5);
Run Code Online (Sandbox Code Playgroud)
我该怎么办?我不在乎性能。
咖喱和咖喱函数的应用是Javascript中有争议的问题。简单来说,有两种相反的观点,我将简要说明两种观点。
-仅在必要时使用单独的咖喱功能
从其他语言或范例适应概念在原则上是一件好事。但是,这种改编应该使用目标语言的基本手段来完成。这对使用javascript意味着什么?
add3(1)(2)(3); // 6const add3 = x => y => z => x + y + z;-默认情况下使用单独的咖喱实现
建议的$/ uncurry函数存在问题:
const $ = (func, ...args) => args.reduce((f, x) => f(x), func);
const sum = x => y => z => x + y + z;
$(sum, 1, 2, 3); // 6
$(sum, 1, 2)(3); // 6
$(sum, 1)(2, 3); // z => x + y + z
Run Code Online (Sandbox Code Playgroud)
通过这种方式,未经处理的函数只能一次使用无限数量的参数。任何后续呼叫都必须设为一元。该功能完全符合其承诺。但是,它不允许应用咖喱函数,例如JavaScript开发人员习惯的。当前的大多数咖喱实现方式都更加灵活。这是扩展的实现:
const uncurry = f => (...args) => args.reduce(
(g, x) => (g = g(x), typeof g === "function" && g.length === 1
? uncurry(g)
: g), f
);
const sum = uncurry(x => y => z => x + y + z);
sum(1, 2, 3); // 6
sum(1, 2)(3); // 6
sum(1)(2, 3); // 6
Run Code Online (Sandbox Code Playgroud)
如果您喜欢自动取消循环,则此实现有效:一旦未管理的函数本身生成了一个已管理的函数作为返回值,则此已返回的函数将自动被取消管理。如果您希望获得更多控制,则以下实现可能更合适。
最终的非即时实现
const partial = arity => f => function _(...args) {
return args.length < arity
? (...args_) => _(...args.concat(args_))
: f(args);
};
const uncurry = arity => f => partial(arity)(args => args.reduce((g, x) => g(x), f));
const sum = uncurry(3)(x => y => z => x + y + z);
sum(1, 2, 3); // 6
sum(1, 2)(3); // 6
sum(1)(2, 3); // 6
Run Code Online (Sandbox Code Playgroud)
这个很小的参数会为我们带来所需的控制。我认为这是值得的。
其余的咖喱解决方案
我们如何处理超出我们控制范围的功能,因此没有进行手动处理?
const curryN = uncurry(2)(arity => f => partial(arity)(args => f(...args)));
const add = curryN(2, (x, y) => x + y);
const add2 = add(2);
add2(4); // 6
Run Code Online (Sandbox Code Playgroud)
幸运的是,我们能够重复使用partial并保持curryN简洁。通过该解决方案,还可以处理可变参数函数或具有可选参数的函数。
奖励:“功能化”和欺骗性方法
要使用方法,我们需要this在显式参数中转换此讨厌的隐式属性。事实证明,我们可以再次重复partial使用适当的实现:
const apply = uncurry(2)(arity => key => {
return arity
? partial(arity + 1)(args => args[arity][key](...args.slice(0, arity)))
: o => o[key]();
});
apply(0, "toLowerCase")("A|B|C"); // "a|b|c"
apply(0, "toLowerCase", "A|B|C"); // "a|b|c"
apply(1, "split")("|")("A|B|C"); // ["A", "B", "C"]
apply(1, "split")("|", "A|B|C"); // ["A", "B", "C"]
apply(1, "split", "|", "A|B|C"); // ["A", "B", "C"]
apply(2, "includes")("A")(0)("A|B|C"); // true
apply(2, "includes", "A", 0, "A|B|C"); // true
Run Code Online (Sandbox Code Playgroud)
在此博客文章中,详细讨论了currying。
| 归档时间: |
|
| 查看次数: |
901 次 |
| 最近记录: |