面向函数范式编程(Functional programming)
2015-07-10 15:36
239 查看
函数编程(简称FP)不只代指Haskell Scala等之类的语言,还表示一种编程思维,软件思考方式,也称面向函数编程。 编程的本质是组合,组合的本质是范畴Category,而范畴是函数的组合。
首先,什么是函数式编程,这并没有唯一定义,它只是广泛聚合了一些编程风格的特性,我们可以将它与面向对象编程OOP进行对比, 两者区别是,OOP主要聚焦于数据的区别,而FP则注重数据结构的一致性。
面向对象:
数据和对数据的操作紧紧耦合
.对象隐藏它们操作的实现细节,其他对象调用这些操作只需要通过接口。
.核心抽象模型是数据自己
核心活动是组合新对象和拓展已经存在的对象,这是通过加入新的方法实现的。
函数编程:
数据与函数是松耦合的
函数隐藏了它们的实现,语言的抽象是函数,以及将函数组合起来表达。
核心抽象模型是函数,不是数据结构
核心活动是编写新的函数。
变量缺省是不变的,减少可变性变量的使用,并发性好
那么OOP和FP在业务领域是否有胜者呢? 我们大部分业务逻辑是这样写:
SELECT orders.order_id, orders.order_date, suppliers.supplier_name
FROM suppliers
RIGHT OUTER JOIN orders
ON suppliers.supplier_id = orders.supplier_id
WHERE orders.order_status = 'INCOMPLETE'
ORDER BY orders.order_date DESC;
SQL是非常类似FP,它能渗透到业务中,它使用一致的数据结构(数据表结构Schema),一些基本函数能组合成很多查询语句,它是declarative声明式的, 也就是说,写出的SQL是告诉数据库我需要什么,数据库就为你返回,而不必指定数据库如何具体去查询。
声明式编程和命令式编程区别? FP的主要特点是它们描述它们要"什么",而不是如何实现。而OO在其方法中,还是使用大部分命令式技术。 下面是命令式技术代码:
var sumOfSquares = function(list) {
var result = 0;
for (var i = 0; i < list.length; i++) {
result += square(list[i]);
}
return result;
};
console.log(sumOfSquares([2, 3, 5]));
函数编程代码如下:
var sumOfSquares = pipe(map(square), reduce(add, 0));
console.log(sumOfSquares([2, 3, 5]));
函数风格的编程特点:
第一等公民是函数
带有闭包的Lambdas/Anonymous函数
不变性,大部分无态处理,没有状态和变量
高并发
无副作用的调用
通过tail call实现递归的性能优化。
模式匹配(Haskell, Erlang)
懒赋值(Miranda, Haskell)
Homoiconicity(类似LISP)
如果说OOP还有很多人可能受静态数据思路影响,那么FP 带来完全是动态事件,FP让我们直接用动词思考,用方法函数解决问题,比如两个帐号之间的转帐,按照DDD等静态领域建模思维,转帐这个功能是放在帐号这个实体类中,还是做一个服务呢?在OOP语言中,我们实现功能总是使用服务Service这样一个概念替代,而且强调无态服务,无态服务实际就是一个只有方法函数没有属性的空架子“类”而已。 2007年的Adam Heroku一篇博文中写道:银行账户之间转帐的老式做法是使用数据库事务,这种做法比较刚性,正确做法是将转帐事件存储起来,如果你是一个面向函数范式的思维者觉得这样做就很正常。---来自" NOSQL存储的基于事件的事务实现 "
。
有很多人将FP归结于数学思维,实际上这只看到其表面,没有看到数学语言这个背后的形式逻辑,编程语言作为和数学同等形式语言,他们的核心基础都是分析哲学的形式逻辑,过去的面向对象很多设计原则也来源于形式逻辑,见:蒯因与引用透明 。
面向对象和面向函数一直在争论,实际上纯粹的OOP和纯粹的FP都是极端的,对于OOP来讲:存在的并一定都是对象,函数就不是对象;对于FP来说:存在的并不总是纯粹的,副作用总是真实存在。总之,面向对象侧重于分解,函数编程侧重于组合。
首先,什么是函数式编程,这并没有唯一定义,它只是广泛聚合了一些编程风格的特性,我们可以将它与面向对象编程OOP进行对比, 两者区别是,OOP主要聚焦于数据的区别,而FP则注重数据结构的一致性。
面向对象:
数据和对数据的操作紧紧耦合
.对象隐藏它们操作的实现细节,其他对象调用这些操作只需要通过接口。
.核心抽象模型是数据自己
核心活动是组合新对象和拓展已经存在的对象,这是通过加入新的方法实现的。
函数编程:
数据与函数是松耦合的
函数隐藏了它们的实现,语言的抽象是函数,以及将函数组合起来表达。
核心抽象模型是函数,不是数据结构
核心活动是编写新的函数。
变量缺省是不变的,减少可变性变量的使用,并发性好
那么OOP和FP在业务领域是否有胜者呢? 我们大部分业务逻辑是这样写:
SELECT orders.order_id, orders.order_date, suppliers.supplier_name
FROM suppliers
RIGHT OUTER JOIN orders
ON suppliers.supplier_id = orders.supplier_id
WHERE orders.order_status = 'INCOMPLETE'
ORDER BY orders.order_date DESC;
SQL是非常类似FP,它能渗透到业务中,它使用一致的数据结构(数据表结构Schema),一些基本函数能组合成很多查询语句,它是declarative声明式的, 也就是说,写出的SQL是告诉数据库我需要什么,数据库就为你返回,而不必指定数据库如何具体去查询。
声明式编程和命令式编程区别? FP的主要特点是它们描述它们要"什么",而不是如何实现。而OO在其方法中,还是使用大部分命令式技术。 下面是命令式技术代码:
var sumOfSquares = function(list) {
var result = 0;
for (var i = 0; i < list.length; i++) {
result += square(list[i]);
}
return result;
};
console.log(sumOfSquares([2, 3, 5]));
函数编程代码如下:
var sumOfSquares = pipe(map(square), reduce(add, 0));
console.log(sumOfSquares([2, 3, 5]));
函数风格的编程特点:
第一等公民是函数
带有闭包的Lambdas/Anonymous函数
不变性,大部分无态处理,没有状态和变量
高并发
无副作用的调用
通过tail call实现递归的性能优化。
模式匹配(Haskell, Erlang)
懒赋值(Miranda, Haskell)
Homoiconicity(类似LISP)
如果说OOP还有很多人可能受静态数据思路影响,那么FP 带来完全是动态事件,FP让我们直接用动词思考,用方法函数解决问题,比如两个帐号之间的转帐,按照DDD等静态领域建模思维,转帐这个功能是放在帐号这个实体类中,还是做一个服务呢?在OOP语言中,我们实现功能总是使用服务Service这样一个概念替代,而且强调无态服务,无态服务实际就是一个只有方法函数没有属性的空架子“类”而已。 2007年的Adam Heroku一篇博文中写道:银行账户之间转帐的老式做法是使用数据库事务,这种做法比较刚性,正确做法是将转帐事件存储起来,如果你是一个面向函数范式的思维者觉得这样做就很正常。---来自" NOSQL存储的基于事件的事务实现 "
。
有很多人将FP归结于数学思维,实际上这只看到其表面,没有看到数学语言这个背后的形式逻辑,编程语言作为和数学同等形式语言,他们的核心基础都是分析哲学的形式逻辑,过去的面向对象很多设计原则也来源于形式逻辑,见:蒯因与引用透明 。
面向对象和面向函数一直在争论,实际上纯粹的OOP和纯粹的FP都是极端的,对于OOP来讲:存在的并一定都是对象,函数就不是对象;对于FP来说:存在的并不总是纯粹的,副作用总是真实存在。总之,面向对象侧重于分解,函数编程侧重于组合。
文章
类型系统和逻辑
范畴category:组合的本质
什么是Monoid ?
什么是Monad?
为什么需要Monad?
面向对象与函数编程的比较
OOP和FP错在哪里?
为什么组合好于继承?
什么是流式思维?
Reactive设计语言与范式
蒯因与引用透明
Java8
Closure Lambda和Monad
分分钟学会Java8的Lambda
Java 8十个lambda表达式案例
Java8教程
使用Java8的Lambda实现的一个简单案例
使用Java8的Lambda实现Monda
使用Java8的Lambda实现模板模式
使用Java8的Lambda实现策略模式
Java8的Lambda和排序
用Java 8 lambda优化JDBC
使用Java8的Lambda简化ReadWriteLock
Java 8的Lambda表达式的阴暗面
用monad替代嵌套回调
更多Java8专题
其他语言
HASKELL入门起步
Scala入门之函数编程
Scala入门之基本概念
更多Scala专题Javascript闭包是什么?
Scala中文教程和手册
苹果Swift语言中文简明教程
参考
Python语言教程手册
Actor专题
面向函数编程系列专题
EDA事件驱动架构
形式逻辑专题
Node.js专题
相关文章推荐
- Windows7下安装Scala 2.9.2教程
- XML 文件解析--含Unicode字符的XML文件
- 分分钟掌握快速排序(Java / Scala 实现)
- Scala极速入门
- Spark初探
- Scala实现REST操作
- Scala method call syntax
- 关于Scala多重继承的菱形问题
- Scala 高阶函数(high-order function)剖析
- Spray.io搭建Rest服务
- Spray.io搭建Rest — 支持Twirl模板并部署
- 搭建hadoop/spark集群环境
- ScalaMP ---- 模仿 OpenMp 的一个简单并行计算框架
- 用Scala实现延迟计算
- SBT学习 [持续更新...]
- Scala创建新的控制结构
- Scala: 一次命令式到函数式的重构
- 浅谈Scala的特质(trait)
- 浅谈Scala 2.8的包对象(package object)