(原)函数式编程
核心概念
- 函数式一等公民(输入输出啥的都可以是函数);
- 纯函数,固定输入带来固定输出;
- 阅读性良好,无并发问题,但效率偏低;
大历史背景
旨在描述问题如何计算:
有两位巨擘对问题的可计算性做了模型化描述
一位是阿兰.图灵(Alan Turing),他提出的图灵机。
另外一个位巨擘,是阿隆佐·邱奇(Alonzo Church)。他提出了Lambda演算(Lambda Calculus)的概念
计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。
对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言;越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Lisp语言。
函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。
概念解读
- 函数:不是面向对象中的函数,强调的是数据之间的映射关系。
- 要求都是纯函数;
- 变量指的是数学中的变量;
- 使用表达式而不要使用语句——即每个都要有返回值;
- 状态保留在中间,而不能依赖外部状态;
优缺点
- 引用透明(不依赖外部)
- 效率高(开发)
- 无并发编程问题;
- 可读性好;
- 占用大量资源;
函数式编程和面向对象编程各有利弊,一个语法更加自由,一个健壮性更好。作为程序员应该对两种编程方式都有所了解,不管是哪种方式,只要能够很好的解决当前的问题就是正确的方式,毕竟对于软件工程来说解决问题是最主要的,用的工具反而没有那么重要,就像对程序员来说语言不重要,重要的是解决问题的思想。
现在这两者的发展趋势是相互借鉴的,许多以面向对象作为基础的语言例如Java等都在新的版本中添加了对函数式编程的支持,而函数式编程则借鉴了一些在面向对象语言里用的一些编译技巧使得程序运行更快。
参考文章
- 函数式编程介绍
- 函数式编程与面向对象编程的比较
- 函数式编程
(更新)命令式编程和声明式编程
前者是指导程序做啥做啥,后者是告诉程序我想要做啥做啥你给我做(通过函数)
命令式编程:命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现。
声明式编程:告诉“机器”你想要的是什么(what),让机器想出如何去做(how)。
举个栗子
//命令式
var numbers = [1,2,3,4,5]
var doubled = []
for(var i = 0; i < numbers.length; i++) {
var newNumber = numbers[i] * 2
doubled.push (newNumber)
}
console.log (doubled) //=> [2,4,6,8,10]
//声明式
var numbers = [1,2,3,4,5]
var doubled = numbers.map (function (n) {
return n * 2
})
console.log (doubled) //=> [2,4,6,8,10]
- 命令式多用于描述业务逻辑;
- 声明式更加抽象;
- 声明式不包含循环;
- 声明式不保存变量值,也不改变外部数值;
- SQL就是典型的声明式;
//声明式
SELECT * from dogs
INNER JOIN owners
WHERE dogs.owner_id = owners.id
//命令式
//dogs = [{name: 'Fido', owner_id: 1}, {...}, ... ]
//owners = [{id: 1, name: 'Bob'}, {...}, ...] var dogsWithOwners = []
var dog, owner
for(var di=0; di < dogs.length; di++) {
dog = dogs[di]
for(var oi=0; oi < owners.length; oi++) {
owner = owners[oi]
if (owner && dog.owner_id == owner.id) {
dogsWithOwners.push ({
dog: dog,
owner: owner
})
}
}}
}
声明式和函数式
- 思想一致,关注做什么而不是怎么做;
- 函数式更强调函数的一等公民地位,直接对函数操作;
参考文章
- 声明式编程和命令式编程的比较
- 编程范式:命令式编程(Imperative)、声明式编程(Declarative)和函数式编程(Functional)