资讯专栏INFORMATION COLUMN

函数式编程术语解析

Tangpj / 816人阅读

摘要:在函数式编程语言中,这一特性可用于构造无限列表。学习网址,是一个拥有和函数的数据类型,类似于,但它会输出非嵌套形式的结果在其他函数式编程语言中,也被称为,也被称为和。

原文连接

[TOC]

Arity

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

</>复制代码

  1. const sum = (a, b) => a + b;
  2. const Arity = sum.length;
  3. console.log(Arity);
  4. // 输出结果为 2
Higher-Order Functions

高阶函数,此类函数可以接收其他函数作为参数,也可以返回一个函数作为返回值:

</>复制代码

  1. const filter = (predFunc, list) => {
  2. const results = [];
  3. list.forEach((listItem) => {
  4. if (predFunc(listItem)) {
  5. results.push(listItem);
  6. }
  7. });
  8. return results;
  9. }
  10. // filter 这个函数就是将一个函数作为参数传入
  11. // 但这都么有什么,主要是后面is函数返回一个函数
  12. const is = (type) => (x) => Object(x) instanceof type;
  13. // is这个函数就是将一个函数作为返回值返回到下面的调用之中
  14. filter(is(Number), [0, "1", 2, null]);
  15. // 上面函数调用的结果是 [0, 2]
Partial Application

偏函数,在原函数的基础上预填充(pre-filling)部分参数并返回的新函数:

</>复制代码

  1. // 下面是一个创建偏函数的辅助函数,下面函数将一个函数和这个函数所需要的除了最后一个参数的参数传入,返回一个新的函数,这个新的函数的参数为原函数的最后一个参数
  2. const partial = (func, ...args) => (...moreArgs) => func(...args, ...moreArgs);
  3. // 写一个将三个数字相加的函数
  4. const add3 = (a, b, c) => a + b + c;
  5. // 预填充 (add3, 2, 3) 三个参数,空置最后一个参数,返回一个新的函数,重点是返回一个新的函数
  6. const fivePlus = partial(add3, 2, 3); // (c) => 2 + 3 + c
  7. fivePlus(4);
  8. // => 9
Currying

柯里化,将一个接收多个参数的函数转化为单参数函数的方式,转化后的函数每次只接收一个参数,然后返回一个新函数,新函数可以继续接收参数,直到接收到所有的参数:

</>复制代码

  1. const sum = (a, b) => a + b;
  2. sum(2, 3);
  3. // => 6
  4. const curriedSum = (a) => (b) => a + b;
  5. curriedSum(40)(2);
  6. // => 42.
  7. const add2 = curriedSum(2);
  8. // (b) => 2 + b
  9. add2(10);
  10. // => 12
Function Composition

函数合成,接收多个函数作为参数并返回一个新函数的方式,新函数按照传入的参数顺序,从右往左依次执行,前一个函数的返回值是后一个函数的输入值:

</>复制代码

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

一个纯函数需要满足两个条件,第一是函数的返回值只能由输入值(函数接收的参数)决定,也就是说纯函数接收相同的参数会返回相同的值;第二是纯函数不会对自身作用域之外的运行环境产生副作用(side effects),比如说不会改变外部环境中变量的值,这会被认为是不安全的行为:
纯函数示例:

</>复制代码

  1. const greet = (name) => "Hi, " + name ;
  2. greet("Brianne")
  3. // => "Hi, Brianne"
Side effects

如果函数或表达式与其自身作用域之外的可变数据(mutable data)发生了读写操作,那么此时函数和表达式就产生了副作用:

</>复制代码

  1. let greeting;
  2. const greet = () => greeting = "Hi, " + window.name;
  3. // greet() 执行时更改了外部环境的变量
  4. greet();
  5. // => "Hi, Brianne"
  6. // new Date() 是可变数据
  7. const differentEveryTime = new Date();
Point-Free Style

point-free style 是一种不显式向函数传递参数的代码风格,通常需要柯里化和高阶函数来实现:

</>复制代码

  1. const map = (fn) => (list) => list.map(fn);
  2. const add = (a) => (b) => a + b;
  3. // Not points-free
  4. // numbers 是一个显式传递的参数
  5. const incrementAll = (numbers) => map(add(1))(numbers);
  6. // Points-free
  7. // add(1) 的返回值隐式传递给了 map,作为 map 的 list 参数
  8. const incrementAll2 = map(add(1));
Predicate

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

</>复制代码

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

常量,初始化后不能再次执行赋值操作的数据类型:

</>复制代码

  1. const five = 5;
  2. const john = { name: "John", age: 30 };
  3. // 因为常量不可变,所以下面表达式一定为 true
  4. john.age + five === ({ name: "John", age: 30 }).age + (5);

常量具有 referentially transparent 的特性,也就是说将程序中出现的常量替换为它们实际的值,并不会影响程序的结果。译者话外:实际上在 JavaScript 中的 const 所声明的常量并不是完全稳定的,使用 Immutable.js 演示更加恰当:

</>复制代码

  1. // 这里的fromJS(), get()函数都是immutable.js所提供的方法
  2. const five = fromJS(5);
  3. const john = fromJS({name: "John", age: 30});
  4. john.get("age") + five === ({ name: "John", age: 30 }).age + (5);
Functor

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

</>复制代码

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

JavaScript 中最常见的 functor 就是数组类型的实例:

</>复制代码

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

lift 发生在你将值放入 functor 的时候,如果你将函数 lift 进了 Applicative Functor,那么就可以使用这个函数处理传递给这个 functor 的值。某些 lift 的实现拥有 lift 或 liftA2 函数,便于在 functor 上执行相关的函数:

</>复制代码

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

lift 一个单参数的函数非常类似于 map 操作:

</>复制代码

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

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

</>复制代码

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

惰性求值,是一种按需执行的求值策略,只有需要某个值时才会执行相关的表达式。在函数式编程语言中,这一特性可用于构造无限列表。

</>复制代码

  1. const rand = function*() {
  2. while (true) {
  3. yield Math.random();
  4. }
  5. }
  6. const randIter = rand();
  7. randIter.next().value;
  8. // 每次执行 next() 函数都会返回一个新的随机数
  9. // 有且只有在执行 next() 的时候才会返回新值
  10. // function* 声明(function关键字后跟一个星号)定义一个generator
  11. // (生成器)函数,返回一个Generator对象。
  12. // 学习网址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/function*
Monad

Monad,是一个拥有 of 和 chain 函数的数据类型,chain 类似于 map,但它会输出非嵌套形式的结果:

</>复制代码

  1. ["cat,dog", "fish,bird"].chain((a) => a.split(","))
  2. // => ["cat", "dog", "fish", "bird"]
  3. ["cat,dog", "fish,bird"].map((a) => a.split(","))
  4. // => [["cat", "dog"], ["fish", "bird"]]

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

Isomorphism

同构转换,相同数据下不同结构之间的转换。举例来说,2D 坐标既可以存储为数组 [2, 3] 也可以存储为 { x: 2, y: 3 }:

</>复制代码

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

Setoid,拥有 equals 函数的数据类型,可用于与其他同类型的数据进行比较。为 Array 类型添加 equals 函数使其成为 Setoid:

</>复制代码

  1. Array.prototype.equals = (arr) => {
  2. const len = this.length
  3. if (len !== arr.length) {
  4. return false
  5. }
  6. for (let i = 0; i < len; i++) {
  7. if (this[i] !== arr[i]) {
  8. return false
  9. }
  10. }
  11. return true
  12. }
  13. [1, 2].equals([1, 2])
  14. // => true
  15. [1, 2].equals([0])
  16. // => false
Semigroup

Semigroup,拥有 concat 函数的数据类型,可以与同类型数据进行合并:

</>复制代码

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

Foldable,拥有 reduce 函数的数据类型,可以将 Foldable 的实例转换为其他数据类型:

</>复制代码

  1. const sum = (list) => list.reduce((acc, val) => acc + val, 0);
  2. sum([1, 2, 3])
  3. // => 6

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80714.html

相关文章

  • 翻译连载 |《你不知道的JS》姊妹篇 |《JavaScript 轻量级函数编程》- 第 1 章:

    摘要:所以我觉得函数式编程领域更像学者的领域。函数式编程的原则是完善的,经过了深入的研究和审查,并且可以被验证。函数式编程是编写可读代码的最有效工具之一可能还有其他。我知道很多函数式编程编程者会认为形式主义本身有助于学习。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson - 《You-Dont-Know-JS》作者 关于译者:这是一个流淌着沪江血液...

    omgdog 评论0 收藏0
  • 前端开发周报:JavaScript编程术语和web图片优化

    摘要:函数式编程术语大全函数式编程有许多优点,它也越来越流行了。然而,每个编程范式都有自己独特的术语,函数式编程也不例外。作用域有两种类似全局作用域和局部作用域。目前最重要的应用场景之一,就是在的握手阶段,客户端服务端利用算法交换对称密钥。 1、JavaScript 函数式编程术语大全 函数式编程(FP)有许多优点,它也越来越流行了。然而,每个编程范式都有自己独特的术语,函数式编程也不例外。...

    kbyyd24 评论0 收藏0
  • 前端开发周报:JavaScript编程术语和web图片优化

    摘要:函数式编程术语大全函数式编程有许多优点,它也越来越流行了。然而,每个编程范式都有自己独特的术语,函数式编程也不例外。作用域有两种类似全局作用域和局部作用域。目前最重要的应用场景之一,就是在的握手阶段,客户端服务端利用算法交换对称密钥。 1、JavaScript 函数式编程术语大全 函数式编程(FP)有许多优点,它也越来越流行了。然而,每个编程范式都有自己独特的术语,函数式编程也不例外。...

    kelvinlee 评论0 收藏0
  • js函数编程术语总结

    摘要:而纯函数,主要强调相同的输入,多次调用,输出也相同且无副作用。对于组合可能不返回值的函数很有用在其它的一些地方,也称为,也称为,也称为 参考文档1 参考文档2 函数式编程术语 高阶函数 Higher-Order Functions 以函数为参数的函数 返回一个函数的函数 函数的元 Arity 比如,一个带有两个参数的函数被称为二元函数 惰性求值 Lazy evaluation 是...

    番茄西红柿 评论0 收藏0
  • 翻译连载 |《你不知道的JS》姊妹篇 |《JavaScript 轻量级函数编程》- 第 2 章:函

    摘要:从某些方面来讲,这章回顾的函数知识并不是针对函数式编程者,非函数式编程者同样需要了解。什么是函数针对函数式编程,很自然而然的我会想到从函数开始。如果你计划使用函数式编程,你应该尽可能多地使用函数,而不是程序。指的是一个函数声明的形参数量。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson - 《You-Dont-Know-JS》作者 关于译者:...

    Riddler 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<