Skip to content

柯里化与函数式编程 #7

@ilcherry

Description

@ilcherry

柯里化

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

看看下面这道题

const sum = (a, b) => {
  return a + b;
};

sum(1,2) // 3

声明了一个计算函数 sum,计算传入 a、b 两个参数的和。
现在我们做一个小小的改动,改成 sum(a)(b),看看实现

const sum = a => {
  return b => {
    return a + b;
  }
}

const compute = sum(1);

compute(2); // 3

两个参数的情况,用一个闭包就可以实现,当有 n 个参数呢?

// 伪代码

const sum = arg1 => {
  return arg2 => {
    return arg3 => {
      return ...
    }
  }
}

// 这显然不合理

underscore.js 中提供了这样的一个柯里化函数 _.compose 帮我们优雅的完成函数处理
我们来分析 _.compose 方法的实现

// underscore.js v1.9.2

/* 
  它可以处理 n 个传入的函数,从右往左依次处理
*/
_.compose = function() {
  var args = arguments;
  var start = args.length - 1;
  return function() {
    var i = start;
    /* 
      上一个函数的返回值是下一个函数的参数
    */
    var result = args[start].apply(this, arguments);
    while (i--) result = args[i].call(this, result);
    return result;
  };
};

首先柯里化函数本身是一个函数,返回值是一个新函数。这就要求在语法层面,函数必须是
一等公民。_.compose 方法里,args 是传入参数函数的类数组,通过 while 循环,从
右往左一次调用传入的参数函数,上一个参数函数的返回值是下一个参数函数的参数。

柯里化与函数式编程

函数式编程是一种编程范式。区别于 C 语言的面向过程编程和 java 的面向对象编程。而
JavaScript 语言是一种多范式的编程语言。而在函数式编程中会产生"柯里化"这种用法

函数式编程需要有如下的前提条件:

  • 函数是一等公民
  • 必须是纯函数

在 JavaScript 这门编程语言中,部分语法满足上述条件,所以 JavaScript 可以书写函数式风格的代码

假设我们有这么个需求,有一系列书存在数组中,现在需要对这个对象数组进行一些修改,找出计算机类的书,并按照价钱的高低排序。我们用函数式的思想来完成这个需求:

const { compose, filter, sortBy } = require('underscore');

const books = [
  {
    title: '《编译原理》',
    price: 89,
    kind: 'computer science'
  },
  {
    title: '《数据结构与算法分析》',
    price: 35,
    kind: 'computer science'
  },
  {
    title: '《原则》',
    price: 98,
    kind: 'Humanities and Social Sciences'
  },
];

const getCSBooks = compose(
  book => sortBy(book, b => b.price),
  book => filter(book, b => b.kind === 'computer science')
);

getCSBooks(books); 

/* 
[
  {
    title: "《数据结构与算法分析》",
    price: 35,
    kind: "computer science"
  },
  {
    title: "《编译原理》",
    price: 89,
    kind: "computer science"
  }
];

*/

但是,在 js 的世界里,纯函数并不多,而带有副作用的函数随处可见。副作用是在计算结果的过程中,系统状态的一种变化,或者与外部世界进行的可观察的交互。副作用包含不止于:

  • 更改文件系统
  • 往数据库插入记录
  • 发生一个 http 请求
  • 可变数据
  • 打印 log
  • 获取用户输入
  • DOM 查询
  • 访问系统状态
    ......

总结

综合来看,遵守函数式编程的风格的代码在前端领域目前仅有用在对数据进行简单处理。

参考链接

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions