函数式编程术语剖析

原文衔接

[TOC]

Arity

指函数的参数数目,由 -ary 和 -ity 这两个英文后缀拼接而成:

const sum = (a, b) => a + b;
const Arity = sum.length;
console.log(Arity);
// 输出效果为 2

Higher-Order Functions

高阶函数,此类函数能够吸收其他函数作为参数,也能够返回一个函数作为返回值:

const filter = (predFunc, list) => {
  const results = [];
  list.forEach((listItem) => {
    if (predFunc(listItem)) {
      results.push(listItem);
    }
  });
  return results;
}
// filter 这个函数就是将一个函数作为参数传入
// 但这都么有什么,主假如背面is函数返回一个函数

const is = (type) => (x) => Object(x) instanceof type;
// is这个函数就是将一个函数作为返回值返回到下面的挪用当中

filter(is(Number), [0, '1', 2, null]);
// 上面函数挪用的效果是 [0, 2]

Partial Application

偏函数,在原函数的基础上预添补(pre-filling)部份参数并返回的新函数:

// 下面是一个建立偏函数的辅佐函数,下面函数将一个函数和这个函数所须要的除了末了一个参数的参数传入,返回一个新的函数,这个新的函数的参数为原函数的末了一个参数
const partial = (func, ...args) => (...moreArgs) => func(...args, ...moreArgs);
// 写一个将三个数字相加的函数
const add3 = (a, b, c) => a + b + c;
// 预添补 (add3, 2, 3) 三个参数,空置末了一个参数,返回一个新的函数,重点是返回一个新的函数
const fivePlus = partial(add3, 2, 3); // (c) => 2 + 3 + c
fivePlus(4);
// => 9

Currying

柯里化,将一个吸收多个参数的函数转化为单参数函数的体式格局,转化后的函数每次只吸收一个参数,然后返回一个新函数,新函数能够继承吸收参数,直到吸收到一切的参数:

const sum = (a, b) => a + b;
sum(2, 3);
// => 6
const curriedSum = (a) => (b) => a + b;
curriedSum(40)(2);
// => 42.
const add2 = curriedSum(2);
// (b) => 2 + b
add2(10);
// => 12

Function Composition

函数合成,吸收多个函数作为参数并返回一个新函数的体式格局,新函数根据传入的参数递次,从右往左顺次实行,前一个函数的返回值是后一个函数的输入值:

const compose = (f, g) => (a) => f(g(a));
const floorAndToString = compose((val) => val.toString(), Math.floor);
floorAndToString(121.212121);
// => "121"

Purity

一个纯函数须要满足两个前提,第一是函数的返回值只能由输入值(函数吸收的参数)决议,也就是说纯函数吸收雷同的参数会返回雷同的值;第二是纯函数不会对本身作用域以外的运转环境发作副作用(side effects),比如说不会转变外部环境中变量的值,这会被认为是不安全的行动:
纯函数示例:

const greet = (name) => "Hi, " + name ;
greet("Brianne")
// => "Hi, Brianne"

Side effects

假如函数或表达式与其本身作用域以外的可变数据(mutable data)发作了读写操纵,那末此时函数和表达式就发作了副作用:

let greeting;
const greet = () => greeting = "Hi, " + window.name;
// greet() 实行时更改了外部环境的变量
greet();
// => "Hi, Brianne"
// new Date() 是可变数据
const differentEveryTime = new Date();

Point-Free Style

point-free style 是一种不显式向函数通报参数的代码作风,一般须要柯里化和高阶函数来完成:

const map = (fn) => (list) => list.map(fn);
const add = (a) => (b) => a + b;
// Not points-free
// numbers 是一个显式通报的参数
const incrementAll = (numbers) => map(add(1))(numbers);
// Points-free
// add(1) 的返回值隐式通报给了 map,作为 map 的 list 参数
const incrementAll2 = map(add(1));

Predicate

断言,一个返回布尔值的函数:

const predicate = (a) => a > 2;
[1, 2, 3, 4].filter(predicate);
// => [3, 4]

Constant

常量,初始化后不能再次实行赋值操纵的数据范例:

const five = 5;
const john = { name: 'John', age: 30 };
// 由于常量不可变,所以下面表达式一定为 true
john.age + five === ({ name: 'John', age: 30 }).age + (5);

常量具有 referentially transparent 的特征,也就是说将顺序中涌现的常量替换为它们现实的值,并不会影响顺序的效果。译者话外:现实上在 JavaScript 中的 const 所声明的常量并非完整稳固的,运用 Immutable.js 演示越发适当:

// 这里的fromJS(), get()函数都是immutable.js所供应的要领
const five = fromJS(5);
const john = fromJS({name: 'John', age: 30});
john.get('age') + five === ({ name: 'John', age: 30 }).age + (5);

Functor

functor 都具有 map 函数,并且在实行 map 之后会返回一个新的 functor:

object.map(x => x) === object;
object.map(x => f(g(x))) === object.map(g).map(f);

JavaScript 中最罕见的 functor 就是数组范例的实例:

[1, 2, 3].map(x => x);
// => [1, 2, 3]
const f = x => x + 1;
const g = x => x * 2;
[1, 2, 3].map(x => f(g(x)));
// => [3, 5, 7]
[1, 2, 3].map(g).map(f);     
// => [3, 5, 7]

Lift

lift 发作在你将值放入 functor 的时刻,假如你将函数 lift 进了 Applicative Functor,那末就能够运用这个函数处置惩罚通报给这个 functor 的值。某些 lift 的完成具有 lift 或 liftA2 函数,便于在 functor 上实行相干的函数:

const mult = (a, b) => a * b;
const liftedMult = lift(mult);
// => this function now works on functors like array
liftedMult([1, 2], [3]);
// => [3, 6]
lift((a, b) => a + b)([1, 2], [3, 4]);
// => [4, 5, 5, 6]

lift 一个单参数的函数异常类似于 map 操纵:

const increment = (x) => x + 1;
lift(increment)([2]);
// => [3]
[2].map(increment);
// => [3]

Lambda

匿名函数,本质上是一个 value:

function(a){
  return a + 1;
};
(a) => a + 1;
// Lambda 常用语高阶函数中
[1, 2].map((a) => a + 1);
// = [2, 3]
// Lambda 作为 value 被赋值给变量
let addOne = (a) => a + 1;

Lazy evaluation

惰性求值,是一种按需实行的求值战略,只要须要某个值时才会实行相干的表达式。在函数式编程语言中,这一特征可用于组织无穷列表。

const rand = function*() {
    while (true) {
        yield Math.random();
    }
}
const randIter = rand();
randIter.next().value;
// 每次实行 next() 函数都邑返回一个新的随机数
// 有且只要在实行 next() 的时刻才会返回新值
// function* 声明(function关键字后跟一个星号)定义一个generator
// (生成器)函数,返回一个Generator对象。
// 进修网址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/function*

Monad

Monad,是一个具有 of 和 chain 函数的数据范例,chain 类似于 map,但它会输出非嵌套情势的效果:

['cat,dog', 'fish,bird'].chain((a) => a.split(','))
// => ['cat', 'dog', 'fish', 'bird']
['cat,dog', 'fish,bird'].map((a) => a.split(','))
// => [['cat', 'dog'], ['fish', 'bird']]

在其他函数式编程语言中,of 也被称为 return,chain 也被称为 flatmap 和 bind。

Isomorphism

同构转换,雷同数据下差别构造之间的转换。举例来说,2D 坐标既能够存储为数组 [2, 3] 也能够存储为 { x: 2, y: 3 }:

const pairToCoords = (pair) => ({x: pair[0], y: pair[1]})
const coordsToPair = (coords) => [coords.x, coords.y]
coordsToPair(pairToCoords([1, 2]))
// => [1, 2]
pairToCoords(coordsToPair({x: 1, y: 2}))
// => { x: 1, y: 2 }

Setoid

Setoid,具有 equals 函数的数据范例,可用于与其他同范例的数据举行比较。为 Array 范例增加 equals 函数使其成为 Setoid:

Array.prototype.equals = (arr) => {
    const len = this.length
    if (len !== arr.length) {
        return false
    }
    for (let i = 0; i < len; i++) {
        if (this[i] !== arr[i]) {
            return false
        }
    }
    return true
}
[1, 2].equals([1, 2])
// => true
[1, 2].equals([0])
// => false

Semigroup

Semigroup,具有 concat 函数的数据范例,能够与同范例数据举行兼并:

[1].concat([2])
// => [1, 2]

Foldable

Foldable,具有 reduce 函数的数据范例,能够将 Foldable 的实例转换为其他数据范例:

const sum = (list) => list.reduce((acc, val) => acc + val, 0);
sum([1, 2, 3]) 
// => 6
    原文作者:张小胖爱逼逼
    原文地址: https://segmentfault.com/a/1190000007324713
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞