关于"函数式编程"编程的理解

什么是"函数式编程"?

函数式编程是一种风格范式,没有一个标准的教条式定义。函数式编程是一种编程范式,它将电脑运算视为函数运算,并且避免使用程序状态以及易变对象。其中,λ演算是该语言最重要的基础。而且λ演算的函数可以接受函数作为输入的参数和输出的返回值。

函数式编程只是一系列想法,而不是一套严苛的规定。

函数式编程具有什么样的特点?

函数是"第一等公民"

函数为第一公民是函数式编程的基础

如果公民分等级,一等公民什么都可以做,次等公民这不能做那不能做。

例如JavaScript的函数也是对象,可以有属性,可以赋值给一个变量,可以放在数组里作为元素,可以作为其他对象的属性,什么都可以做,别的对象能做的它能做,别的对象不能做的它也能做。这不就是一等公民的地位嘛。

只用"表达式",不用"语句"

"表达式"(expression)是一个单纯的运算过程,总是有返回值;"语句"(statement)是执行某种操作,没有返回值。函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。

没有"副作用"

所谓"副作用"(side effect),指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。

但是要声明一点,函数式编程并不是不需要副作用, 而是副作用隔离,只是在需要时限制它们。需要有副作用,因为没有它们,我们的程序将只能进行计算。例如, 我们经常必须写数据库,与外部系统集成或写文件。与外界通过接口的形式交互才能将我们的计算展示出去。所以很多倾向无副作用的语言的中心思想是把“作用”与“副作用”分离开来处理

典型副作用例子: 调用全局变量, 调用I/O操作, 调用对象属性,

不修改状态

在副作用中已经提到,函数式编程只是返回新的值,不修改系统变量。因此,不修改变量,也是它的一个重要特点。

引用透明性

函数程序通常还加强引用透明性,即如果提供同样的输入,那么函数总是返回同样的结果。就是说,表达式的值不依赖于可以改变值的全局状态。

有哪些技术使用了函数式编程思想呢?

纯函数

函数内部传入指定的值,就会返回确定唯一的值.

高阶函数

接受函数作为参数或返回函数的函数称为高阶函数——对函数进行操作的函数。

柯里化

柯里化是一种关于函数的高阶技术。它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c), 柯里化不会调用函数, 它只是对函数进行转换。

优点: 当存在大量相同参数时,参数复用或简化。

// curry(f) 柯里化转换函数, 是一个高阶函数
function curry(f) {
  return function(a) {
    return function(b) {
      return f(a, b);
    };
  };
}

// 原始函数
function sum(a, b) {
  return a + b;
}

// 调用柯里化转
let curriedSum = curry(sum);

// 执行转化后的函数
alert( curriedSum(1)(2) ); // 3

函数组合

将多个函数组合成一个函数, 像流水线一样工作。主要应用了函数做为参数传递, 并返回新函数

闭包

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。

function makeFunc() {
  var name = "Mozilla";
  function displayName() {
    alert(name);
  }
  return displayName;
}

var myFunc = makeFunc();
myFunc();

例子中, myFunc 是执行 makeFunc 时创建的 displayName 函数实例的引用。displayName 的实例维持了一个对它的词法环境(变量 name 存在于其中)的引用。因此,当 myFunc 被调用时,变量 name 仍然可用

闭包很有用,因为它允许将函数与其所操作的某些数据(环境)关联起来。这显然类似于面向对象编程。在面向对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。

偏函数

固定一个函数的一些参数,然后产生另一个少参数的函数。主要丝线还是利用了函数作为参数和返回

偏函数与柯里化十分相似

function add(a, b) {
  return a + b;
}

// 执行 add 函数,一次传入两个参数即可
add(1, 2); // 3

// 假设有一个 partial 函数可以做到局部应用, 这里的partial需要我们自己实现
var addOne = partial(add, 1);

addOne(2); // 3

函数式编程的优点

接近自然语言,易于理解

函数式编程的自由度很高,可以写出很接近自然语言的代码。

异步

因为我们不知道什么时候调用完成, 所以我们干脆就将完成后的操作函数以参数的形式传给调用方法, 这样就可以将异步调用和回调写一起了.

易于"并发编程"

函数式编程不需要考虑"死锁"(deadlock),因为它不修改变量,所以根本不存在"锁"线程的问题。不必担心一个线程的数据,被另一个线程修改,所以可以很放心地把工作分摊到多个线程,部署"并发编程"(concurrency)。

扩展阅读

深入理解函数式编程(上)
深入理解函数式编程(下)

此处评论已关闭