Javascript的函数式编程术语解释

  函数式编程(functional programming)很多术语来自于组合数学或范畴理论,下面使用Javacript解释这些术语的含义:

Arity数量

这是代表一个函数的参数数量,从1 2 3数量的单词一次是unary(一元)、binary(二元) ternary(三元)等等,这些单词都有后缀:"-ary"或"-ity",如果一个函数带有两个参数称为binary函数,一个函数带许多可变参数称为"variadic,",而一个binary函数有且只有两个参数。

const sum = (a, b) => a + b;
const arity = sum.length;
console.log(arity);
// => 2 
//sum的参数arity数量是2 

 

高阶函数(HOF:Higher-Order Function)

一个函数将函数作为参数,并且/或者返回也是一个函数,这个函数称为高阶函数:

const filter = (pred, xs) => {
  const result = [];
  for (var idx = 0; idx < xs.length; idx += 1) {
    if (pred(xs[idx])) {
      result.push(xs[idx]);
    }
  }
  return result;
};

该函数调用:

filter(is(Number), [0, '1', 2, null]); //=> [0, 2]

其中is函数是作为filter的参数函数:

const is = type => x => Object(x) instanceof type;
因此,filter函数结果是[0,2],这个结果可以不是一个函数。

 

Partial应用

对一个有多个参数的函数,如果我们从其只获得更少参数的函数,这个过程处理称为partial应用.

let sum = (a, b) => a + b;
// partially只应用了 `a`参数为 `40` ,'b'参数没有使用
let partial = sum.bind(null, 40);
// 现在使用了`b` 参数
partial(2); //=> 42

注意,Javascript的bind call和apply都是类似,其第一个参数被绑定的函数,这里设为null,没有使用,后面开始按照函数的参数固定顺序对应了。

 

Currying柯里化

转换一个带有多个参数的函数到同样的函数但是只带有一个参数了,不要和partial应用混淆,后者能产生多于一个参数的函数。

let sum = (a, b) => a + b;
let curriedSum = (a) => (b) => a + b;
curriedSum(40)(2) // 42. 

 

Composition组合

结合两个给定类型(某种函数)的值变成同样类型的第三方值。

组合最直接类型称为"正常函数组合".允许你组合多个只有一个单值参数和只返回一个单值的函数。

const compose = (f, g) => a => f(g(a)) // 组合定义,定义了f(g(a))两个组合
const floorAndToString = compose((val)=> val.toString(), Math.floor) //使用组合
floorAndToString(121.212121) // "121" 

 

Purity纯洁

一个函数定义为纯函数:如果函数返回值仅仅由其输入值决定,而没有任何副作用。

let greet = "yo ";
greet.toUpperCase(); // YO; 
greet // yo; 

上述greet是纯的,因为其输出由输入决定。相反案例:

let numbers = [1, 2, 3];
numbers.splice(0); // [1, 2, 3] 
numbers // [] 

这里numbers函数输入是[1,2,3],numbers.splice(0)是一个有副作用的操作,改变了numbers内部状态,导致numbers输出改变。

 

副作用Side effect

一个函数或表达式如果出现下面情况被认为有副作用:除了返回一个值,它还修改了内部状态,或者有一个和外部函数有一个能够被观察的交互,所谓能够被观察,也就是能被外界植入改变状态的可能,提供了改变内部状态的可能。一般IO操作是有副作用的。

 

幂等Idempotency

能够多次使用同样的输入参数无副作用地执行多次。

f(f(x)) = f(x)

Math.abs(Math.abs(10))

 

Point-Free 风格

并没有显式定义参数的函数,通常需要柯里化和高阶函数

// 假定如果 
let map = fn => list => list.map(fn);
let add = (a, b) => a + b;
// 那么
// Not points-free - `numbers`是显式参数
let incrementAll = (numbers) => map(add(1))(numbers);
// Points-free - 这个集合list是隐式参数
let incrementAll2 = map(add(1));

incrementAll是使用参数numbers,它就不是points-free,而incrementAll2是有函数和返回值,但是没有提到它的参数,因此它是points-free

points-free函数定义了像没有函数或=>的正常赋值,其实这是定义了一个函数。

 

以上是有关组合数学的相关术语,范畴相关术语见下一页。

下一页

Javascript专题

函数编程专题