最近有看到一些柯里化的文章, 怎么说呢, 感觉很奇怪. 一篇是阿里云的译文, 文章末尾给出了这样一个 "curry":
- function curry(fn, ...args) {
- return (..._arg) => {
- return fn(...args, ..._arg);
- }
- }
作者前面明明例举了柯里化和部分应用的区别, 结果最后说我们实现下柯里化吧, 然后写了个部分应用...... 太假了, 我忍不住评论了一下:
然后今天看到我们组欢哥的文章 https://www.jianshu.com/p/18165d23d085 , 说实话看了一下开头这段代码我就不太有耐心看下面具体的分析了:
- // 定义占位符
- var _ = '_';
- function magician3 (targetfn, ...preset) {
- var numOfArgs = targetfn.length;
- var nextPos = 0; // 下一个有效输入位置的索引, 可以是'_', 也可以是 preset 的结尾
- // 查看是否有足够的有效参数
- if (preset.filter(arg=> arg !== _).length === numOfArgs) {
- return targetfn.apply(null, preset);
- } else {
- // 返回'helper'函数
- return function (...added) {
- // 循环并将 added 参数添加到 preset 参数
- while(added.length> 0) {
- var a = added.shift();
- // 获取下一个占位符的位置, 可以是'_'也可以是 preset 的末尾
- while (preset[nextPos] !== _ && nextPos <preset.length) {
- nextPos++
- }
- // 更新 preset
- preset[nextPos] = a;
- nextPos++;
- }
- // 绑定更新后的 preset
- return magician3.call(null, targetfn, ...preset);
- }
- }
- }
这是在干嘛...... 然后欢哥他们发现了这段代码有 bug, 分析了一通, 解决了 bug, 美好的青春啊朋友们, 出去喝酒蹦迪大保健不好么, 非得这么挥霍生命么......
在我们自己实现之前, 对柯里化没什么概念的同学可以看下 https://en.wikipedia.org/wiki/Currying (要看英文 wiki, 中文 wiki 对柯里化的解释写得又乱又不准确, 容易和部分应用混淆), 简单来说柯里化就是把一个多参函数转换成接受单参的一系列函数. 它跟部分应用 https://en.wikipedia.org/wiki/Partial_application 的概念不太一样, 部分应用是把一个多参函数 "切" 一刀, 而柯里化是把函数 "切" 好多刀, 直到中间每个函数都是单参的, 最后得到的结果就是所谓的柯里化函数 (curried function). 在 JS 里要手写个 curried function 其实就是手写个高阶函数, 没什么特别的. 那要实现一个通用的 curry, 该怎么做呢, 我不是针对谁, 我是说上面那两个实现都在卖萌......
- const curry = (fn) => {
- if (fn.length <= 1) return fn;
- const generator = (args, REST) => (!REST ? fn(...args) : arg => generator([...args, arg], REST - 1));
- return generator([], fn.length);
- };
这不就三行代码搞定了么 (不算函数声明), 测一下:
- const sum = (a, b, c) => a + b + c;
- const curriedSum = curry(sum);
- const res = curriedSum(1)(2)(3)
- console.log(res); // 6
- const log = (a, b, c) => {
- console.log(a, b, c);
- };
- const curriedLog = curry(log);
- curriedLog('a')('b')('c'); // a b c
好像没啥问题吧......emmmmm...... 欢迎打脸.
由此可见, 在折腾什么 curry 什么 partial application 之前, 还是多琢磨琢磨递归这种基本概念, 顺便附送一个 FP Style 的快排吧, 突然感觉我也挺挥霍青春的......
- const quickSort = (list) => {
- if (!list || !list.length) return [];
- if (list.length === 1) return list;
- const [middle, ...REST] = list;
- const reducer = (acc, x) => (
- x <= middle ?
- { ...acc, left: [...acc.left, x] } :
- { ...acc, right: [...acc.right, x] }
- );
- const { left, right } = REST.reduce(reducer, { left: [], right: [] });
- return [...quickSort(left), middle, ...quickSort(right)];
- };
- const list = [2, 3, 1, 8, 8, 1, 2, 18, 6, 2333];
- const sorted = quickSort(list); // [ 1, 1, 2, 2, 3, 6, 8, 8, 18, 2333 ]
来源: https://juejin.im/post/5bf9bb7ff265da616916e816