Scala 函数式编程

a、什么是函数式编程

函数式编程是一种编程范式(即编写程序的方法论),它主要通过组合方式,将运算过程组合成一系列的函数调用。如下的数学表达式:

(1 + 2) * 3 - 4
传统的过程式编程,可能这样写:

var a = 1 + 2
var b = a * 3
var c = b - 4
而函数编程则就要将每个运算过程定义为不同的函数,然后组合起来使用,返回最终的计算结果。如下
var result = subtract(multiply(add(1,2), 3), 4);
这就是函数式编程。

b、函数式编程和面向对象编程的区别

函数式编程和面向对象编程是两种不同的看待问题的方式,函数式编程强调的是“动词(verbs)”以及如何组合和调用它们。而面向对象编程强调的是”名词(nouns)“以及它们所具有的动作。

面向对象编程中,每个对象都有标识符、方法、状态(成员变量)。在标识对象、对象状态、行为后,对象之间的交互就成了问题,因为交互需要在一个对象里完成。现在常用的方法是创建一个服务类(Service Class),它包含一个跨多个域对象的操作集合。服务类也是一个对象,它没有状态或行为独立于其操作对象的概念。

函数式编程侧重于函数的组合和应用,所有的变量都是不可变的,并且尽可能的消除副作用,这些都有利于并发编程。

举个例子,分别采用面向对象编程和函数式编程的方式,对下面的一句话编程:

一只猫捕捉了一只鸟,并吃了它。
采用面向对象编程的方式,可以从这句话中提取出两个名词:猫、鸟,并且猫具有“捕捉”和“吃”的动作。代码如下:

class Bird
class Cat {
  def catch(b: Bird): Unit = ...
  def eat(): Unit = ...
}
val cat = new Cat
val bird = new Bird
cat.catch(bird)
cat.eat()
采用函数是编程的方式,则应关注“动词”

trait Cat
trait Bird
trait Catch
trait FullTummy

def catch(hunter: Cat, prey: Bird): Cat with Catch
def eat(consumer: Cat with Catch): Cat with FullTummy

val story = (catch _) andThen (eat _)
story(new Cat, new Bird)

c、函数式编程的特点

1、函数是“第一等公民”

所谓的“第一等公民”是指,函数和其它的数据类型一样,处于平等地位,它可以给变量赋值,可以作为参数传入另一个函数,也可以作为别的函数的返回值。

2、只用表达式,不用语句

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

3、没有“副作用”

所谓的“副作用”是指,函数内部与外部的交互,不会改变外部的状态,例如修改外部的成员变量或修改全局变量的值等。

4、引用透明性

引用透明性是指函数的运行不依赖与外部的变量或状态,只依赖与输入的参数,只要输入的参数相同,输入的结果始终是相同的。

关于“引用透明性”的理解,还可详见这篇文章:http://blog.csdn.net/qiruiduni/article/details/46831461


d、函数式编程的优点

1、代码简洁,开发快速

函数式编程大量使用函数,减少了代码的重复,因此程序比较短,开发速度快。

2、接近自然语言,易于理解

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

前文曾经将表达式(1 + 2) * 3 - 4,写成函数式语言:

subtract(multiply(add(1,2), 3), 4)
对它进行变形,不难得到另一种写法:

add(1,2).multiply(3).subtract(4)
这基本就是自然语言的表达了。再看下面的代码,大家应该一眼就能明白它的意思吧:

merge([1,2],[3,4]).sort().search("2")

因此,函数式编程的代码更容易理解。

3、更方便的代码管理

函数式编程不依赖、也不会改变外界的状态,只要给定输入参数,返回的结果必定相同。因此,每一个函数都可以被看做独立单元,很有利于进行单元测试(unit testing)和除错(debugging),以及模块化组合。

4、易于“并发编程”

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

请看下面的代码:

  var s1 = Op1();
  var s2 = Op2();
  var s3 = concat(s1, s2);
由于s1和s2互不干扰,不会修改变量,谁先执行是无所谓的,所以可以放心地增加线程,把它们分配在两个线程上完成。其他类型的语言就做不到这一点,因为s1可能会修改系统状态,而s2可能会用到这些状态,所以必须保证s2在s1之后运行,自然也就不能部署到其他线程上了。

多核CPU是将来的潮流,所以函数式编程的这个特性非常重要。

5、代码的热升级

函数式编程没有副作用,只要保证接口不变,内部实现是外部无关的。所以,可以在运行状态下直接升级代码,不需要重启,也不需要停机。Erlang语言早就证明了这一点,它是瑞典爱立信公司为了管理电话系统而开发的,电话系统的升级当然是不能停机的。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值