Scala 函数式编程

原创 2015年07月10日 10:25:43

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语言早就证明了这一点,它是瑞典爱立信公司为了管理电话系统而开发的,电话系统的升级当然是不能停机的。



版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Scala函数式编程.pdf

  • 2017-05-30 21:30
  • 73.71MB
  • 下载

Scala函数式编程

  • 2017-05-26 10:22
  • 73.71MB
  • 下载

Scala函数式编程课后习题答案(第五章)

Scala函数式编程课后习题答案(第五章)没有按题目细分,比较杂乱。

Scala函数式编程.pdf

  • 2017-06-18 18:12
  • 73.71MB
  • 下载

scala函数式编程-scalaz

  • 2015-10-09 09:33
  • 1.21MB
  • 下载

【学渣笔记】scala动手实战之函数式编程特点与价值

函数式编程的五个鲜明特点:     1.函数是第一等公民。     即函数与其他数据类型一样,处于平等地位,可以赋值给变量,也可以作为参数传入另一个函数,或者作为别的函数的返回值。     2.只用表...

一步步学spark之一scala函数式编程中闭包,Curry3.0

一步步学spark之一scala函数式编程中闭包,Curry 闭包:闭合的一个包 这样定义的话会报错 找不到y 声明了一个全局变量,y捕获到了这个变量,从而使x+y的状态能够正常的变成一个函数...

Scala:函数式编程之下划线underscore

http://blog.csdn.net/pipisorry/article/details/52913548Scala 中下划线的用法 1、存在性类型:Existential typesdef fo...

大数据Spark“蘑菇云”行动-第14课Scala集合上的函数式编程实战及Spark源码鉴赏

大数据Spark“蘑菇云”行动-第14课Scala集合上的函数式编程实战及Spark源码鉴赏
  • zhumr
  • zhumr
  • 2016-08-31 08:38
  • 655

Scala函数式编程

1、函数和变量一样作为Scala语言的一等公民,函数可以直接赋值给变量; 2、函数更长用的方式是匿名函数,定义的时候只需要说明输入参数的类型和函数体即可,不需要名称,但是如果你要使用的话,一...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)