函数式编程(Functional programming)
函数式编程(简称FP)不只代指Haskell Scala等之类的语言,还表示一种编程思维,软件思考方式,也称面向函数编程。 编程的本质是组合,组合的本质是范畴Category,而范畴是函数的组合。
首先,什么是函数式编程,这并没有唯一定义,它只是广泛聚合了一些编程风格的特性,我们可以将它与面向对象编程OOP进行对比,两者区别是,OOP最大优点是多态性和封装;而FP优势是不变性及其声明性风格,两者其实是十字正交,可互补的,可在同一程序中共存。
面向对象:
- 数据和对数据的操作紧紧耦合,封装在一个类Class中(充血模型)。这里的数据是可变的。
- 数据的变化更改需要通过数据的操作方法实现,类以外方法不能直接操作更改一个类内部的数据属性。
- 类或对象隐藏它们操作的实现细节,其他对象调用这些操作只需要通过接口。
- .核心抽象模型是数据和数据的关系。
- 增加功能通常是组合新对象和拓展已经存在的对象,并加入新的方法实现的。
函数编程:
- 数据与函数是松耦合的,两者是分离的,数据是纯数据(失血模型),函数没有与数据封装在一起。这里的数据是不可变的。
- 函数隐藏了它们的内部实现,语言的抽象是函数,以及将函数组合起来表达。
- 核心抽象模型是函数和函数的组合交换。
- 通常增加功能是通过编写新的函数实现。
- 变量缺省是不可变的,一旦赋值就不能再被改变,减少可变性变量的使用会提升并发性。
函数风格的编程特点:
- 第一等公民是函数(不是对象Object或Class)
- 带有闭包的Lambdas/Anonymous函数
- 不变性,大部分无态处理,没有状态和变量(没有可变数据)
- 高并发
- 无副作用的调用(一个函数不会实现两个以上功能)
- 通过tail call实现递归的性能优化。
- 模式匹配(Haskell, Erlang)
- 懒赋值(Miranda, Haskell)
- Homoiconicity(类似LISP)
如果说OOP还有很多人可能受静态数据思路影响,那么FP 带来完全是动态事件,FP让我们直接用动词思考,用方法函数解决问题,比如两个帐号之间的转帐,按照DDD等静态领域建模思维,转帐这个功能是放在帐号这个实体类中,还是做一个服务呢?在OOP语言中,我们实现功能总是使用服务Service这样一个对象实现,而且强调无态服务,无态服务实际就是一个只有函数没有数据的空架子“类”而已。 银行账户之间转帐的老式做法是使用数据库事务,这种做法比较刚性,正确做法是将转帐作为事件存储起来,如果你是一个函数式思维者觉得这样做就很正常。
有很多人将FP归结于数学思维,实际上这只看到其表面,没有看到数学语言这个背后的形式逻辑,编程语言作为和数学同等形式语言,他们的核心基础都是分析哲学的形式逻辑,过去的面向对象很多设计原则也来源于形式逻辑,见:蒯因与引用透明 。
面向对象和面向函数一直在争论,实际上纯粹的OOP和纯粹的FP都是极端的,对于OOP来讲:存在的并一定都是对象,函数就不是对象(没有纯粹的对象);对于FP来说:存在的并不总是纯粹的,副作用总是真实存在(没有纯粹的函数)。总之,面向对象侧重于分解,函数编程侧重于组合,两者配合使用才能发挥各自优点。
Java函数式特点:
- 不可变性:写尽可能多不可变对象。这样可以减少我可以更改程序状态的地方。这样可以减少错误。
- 参照透明性:写尽可能多的纯函数。这些函数就像数学函数一样。对于相同的输入,它们始终具有相同的输出。
- 纯函数和不纯函数:将纯函数与不纯函数分开,可以更轻松地测试代码,并提高了代码的可重用性。
- 函数组合:提高代码的可读性,并且通过组合函数来编写代码更容易。
- Curried Functions:出色的概念,但是在Java中使用它并不自然。
- 惰性求值:在需要时求值。Lambda是在Java中进行惰性求值的方法。
- 高阶函数:在现有函数中接收其他函数作为参数。这些函数通常是实用程序函数。
- 映射,过滤,reduce模式:Java Stream API实现此模式。
- Monads:帮助了解如何安全地处理不纯函数。
- Optional类:FP提供有关如何使用可为空的对象的有效解决方案。总是在可以返回null的方法中返回Optional对象而不是null。
- 铁路Railway编程:可帮助了解Stream API和Optional类的工作方式。
文章
函数式编程 vs 面向对象编程 vs 过程式编程
类型系统和逻辑
函数式编程模式:单位元(幺元)
函数式编程模式:半群
范畴category:组合的本质
什么是Monoid ?
什么是Monad?
为什么需要Monad?
面向对象与函数编程的比较
OOP和FP错在哪里?
为什么组合好于继承?
什么是流式思维?
Reactive设计语言与范式
蒯因与引用透明
为什么我再也不使用MVC框架了?
微服务的最终一致性与事件流
一张图解说Map/filter/reduce
从CRUD编程切换到事件溯源和区块链编程
一篇有关函数式编程的形象生动教程
否定OOP的面向数据编程DOP原理
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语言中文简明教程
Javascript的函数式编程术语解释
Python语言教程手册