术语概念
Functional Programming
越靠下表示背离传统命令式语言更远

Functional Programming( 函数式编程)
> 函数式编程初探——阮一峰 > > 函数式编程
诞生
Terms
Side Effects
在计算机科学与技术中,一个函数或者一个表达式被称为有副作用,常常发生在如下几种情况:
- 修改了部分状态,譬如某个函数修改了全局变量、静态变量、某些传入的参数、引发了一个异常
- 返回了一个类似于
Observable 对象 - 与外部产生了交互,譬如读写文件、发起网络请求或者调用其他包含副作用的方程
在一个具有副作用的函数中,一个程序的行为往往依赖于上下文与历史记录。
Mutable VS Immutable( 可变对象与不可变对象)
顾名思义,不可变对象就是在创建之后其状态不可以再被修改的对象。引用function touchAndLog(touchFn) { let data = { key: 'value' }; touchFn(data); console.log(data.key); // 猜猜会打印什么?}
在不查看 touchFn
的代码的情况下,因为不确定它对 data
做了什么,你是不可能知道会打印什么data
是value
。import { Map} from 'immutable';let a = Map({ select: 'users', filter: Map({ name: 'Cam' })})let b = a.set('select', 'people');a === b; // falsea.get('filter') === b.get('filter'); // true
上面filter
节点。1. Undo/Redo,Copy/Paste,甚至时间旅行这些功能做起来小菜一碟因为每次数据都是不一样的,只要把这些数据放到一个数组里储存起来,想回退到哪里就拿出对应数据即可,很容易开发出撤销重做这种功能。后面我会提供
High-Order Function( 高阶函数)
在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数
-
接受一个或多个函数作为输入
-
输出一个函数
在数学中它们也叫做算子
定义
简单说
特点
函数式编程具有五个鲜明的特点。
所谓“第一等公民”(first class),指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。
举例来说,下面代码中的
> var print = function(i){ console.log(i);}; > > [1,2,3].forEach(print);
“表达式”
原因是函数式编程的开发动机,一开始就是为了处理运算
当然,实际应用中,不做
所谓“副作用”(side effect),指的是函数内部与外部互动
函数式编程强调没有
而无状态性则主要依赖于递归,
上一点已经提到,函数式编程只是返回新的值,不修改系统变量。因此,不修改变量,也是它的一个重要特点。
在其他类型的语言中,变量往往用来保存
> function reverse(string) { > > if(string.length == 0) { > > return string; > > } else { > > return reverse(string.substring(1, string.length)) + string.substring(0, 1); > > } > > }
由于使用了递归,函数式语言的运行速度比较慢,这是它长期不能在业界推广的主要原因。
引用透明
有了前面的第三点和第四点,这点是很显然的。其他类型的语言,函数的返回值往往与系统状态有关,不同的状态之下,返回值是不一样的。这就叫
优点
函数式编程大量使用函数,减少了代码的重复,因此程序比较短,开发速度较快。
如果程序员每天所写的代码行数基本相同,这就意味着
函数式编程的自由度很高,可以写出很接近自然语言的代码。
前文曾经将表达式
> subtract(multiply(add(1,2), 3), 4)
对它进行变形,不难得到另一种写法:
> add(1,2).multiply(3).subtract(4)
这基本就是自然语言的表达了。再看下面的代码,大家应该一眼就能明白它的意思吧:
> merge([1,2],[3,4]).sort().search(“2”)
因此,函数式编程的代码更容易理解。
函数式编程不依赖、也不会改变外界的状态,只要给定输入参数,返回的结果必定相同。因此,每一个函数都可以被看做独立单元,很有利于进行单元测试
实际上,我们在函数式编程中进行构建的是实体与实体之间的关系。在这种意义上,
义,大多数提供了原生的
精确自然的命令式编程,又为什么还需要函数式编程呢?我们举个小例子。
int fab(int n) {
return n == 1 || n == 2 ? 1 : fab(n - 1) + fab(n - 2);
}
这是用
fab::(Num a) => a -> a
fab n = if n == 1 || n == 2 then 1 else fab(n - 1) + fab(n - 2)
看
上去差不多对不对?但是这两个程序在执行的效率方面有着天差地别的差距。为什么呢?
原封不动地机械地去执行。如果想效率提高,你必须自己去分析程序,去人工地减少程序中执行的语句的数量。具体到这个
都会产生两个新的函数调用。这时,实际产生的函数调用的数目是指数级别的!比方说,我们写
fab(5)
fab(4)
fab(3)
fab(2)
fab(1)
fab(2)
fab(3)
fab(2)
fab(1)
我们看到,
那么函数式语言呢?我们说过,函数式语言里面是没有变量的。换句话说,所有的东西都是不变的。因此在执行
fab(5)
fab(4)
fab(3)
fab(2)
fab(1)
fab(3)
总
共只有五次应用。注意我说的是应用而不是调用。因为函数式语言里的函数本意并不是命令式语言里面的“调用”或者“执行子程序”的语义,而是“函数与函数之
间的关系”的意思。比如
所有的计算都是静态的。
了结果。
本质上,这代表了我们提供给函数式语言的程序其实并不是一行一行的“命令”,而只是对数据变换的说明。这样函数式语言可以深入这
些说明中,寻找这些说明中冗余的共性,从而进行优化。这就是函数式语言并不需要精心设计就会比命令式语言高效的秘密。命令式语言当然也可以进行这种优化,
但是因为命令式语言是有边界效应的。而且大部分情况下都是利用边界效应进行计算,因此很难推广这种优化,只有少数几种窥孔优化能取得效果。
放
到这个例子上,因为本质上我们两次的
这个函数返回的值是不会变的!而这是函数式语言主要的特性
以了。这就是上面几乎完全一样的两个程序效率相差如此之大的主要原因。
函数式编程不需要考虑
请看下面的代码:
> var s1 = Op1(); > > var s2 = Op2(); > > var s3 = concat(s1, s2);
由于
多核
函数式编程没有副作用,只要保证接口不变,内部实现是外部无关的。所以,可以在运行状态下直接升级代码,不需要重启,也不需要停机。Erlang语言早就证明了这一点,它是瑞典爱立信公司为了管理电话系统而开发的,电话系统的升级当然是不能停机的。
Reactive Programming( 响应式编程)
> - Wiki-Reactive_programming > - The introduction to Reactive Programming you’ve been missing – 中文版 > - reactive-programming-using-rxjava-and-akka
从定义上来说,维基百科提供了如下的定义:
> Reactive programming is a programming paradigm oriented around data flows and the propagation of change
响应式编程式一种面向数据流与变化传播的编程范式。通俗来说,响应式编程就是面向异步数据流的一种编程方式。响应式编程的原则可以看做是并发编程原则以及异步系统原则的一种组合。响应式编程可以看做高级编程范式面向于需要处理分布式状态以及编排异步数据流的一种自然扩展。一般来说,响应式编程的原则如下:
Responsive & Fault-tolerant: 应用程序应当能够快速地响应用户,即使在高负载以及存在错误的情况下。- Resilient and Scalable: The application should be resilient, in order to stay responsive under various conditions. They also should react to changes in the input rate by increasing or decreasing the resources allocated to service these inputs. Today’s applications have more integration complexity, as they are composed of multiple applications.
- Message Driven: A message-drivenarchitecture is the foundation of scalable, resilient, and ultimately responsive systems.
响应式编程是一种面向异步数据流的编程模型。在实际的编程实现中,响应式编程往往有两种方式,一个是类似于
Functional Reactive Programming
> - functional-reactive-programming