什么是函数式编程

今天在逛微博看别人吐槽.Net开源时发现他们除了说C#,java之外,还提及了Scala.之前从来都没听说过这种语言,后来一查才发现这是一种学习坡度略陡的高逼格语言.

  • Scala是Scalable language(可灵活升级的语言)的简写.
  • 是一种函数式和面向对象的混合语言.
  • 既能拿来写脚本,也能胜任高并发大项目.
  • 个人感觉语法类似Python等一系列语言,没有分号,靠缩进分块等.
  • 主要运行在JVM,也有.Net实现,不过用的少.
  • 可调用所有java library, java也可以调用它的library,与java交互性强.
  • 学习门槛高,但精通后编写程序的代码量可以少很多,比java之类的可以少一半左右.
  • java可以开发的,scala都能开发.(所以说也可以用它来写Android).
  • scale基本上无需定义数据类型,会进行自识别.
  • ……

等等,我这篇blog应该是讲函数式编程.上面的只是勾起大家对Scala的兴趣,关于Scala这门语言,我会在接下来的时间里边学习边总结.

什么是函数式编程

函数式编程是一种编程范式,是一类典型的编程风格,是用一系列嵌套的函数来代替运算过程,避免使用全局变量和状态. (想系统学习编程范式可以看斯坦福的一门高评价公开课:编程范式)

例如用熟悉的Android来解释:

//SQL查询语句的ActiveAndroid实现
//原生SQL语句为"SELECT * FROM USER WHERE age = 45"
Select().from(User.class).where("age = ?", user.getAge()).execute();

这就将一个SQL语句的直接运算替换成了一系列函数的嵌套.

这里由于函数式编程是一种编程风格,所以说就算是面向对象编程语言也是可以通过一定的方法来使用函数式编程,这些没有绝对的界限,只是实现的难易程度不同而已.

函数式编程特点

1. 函数作为第一对象

在函数式编程中,函数是第一对象,类似于面向对象编程中的对象,他几乎被用作一切,包括最简单的计算,甚至连变量都被计算所取代,在函数间传递的不再是变量,而是一个个的函数。

var upCase = function(i){ i.toUpperCase(); };
['a','b','c'].forEach(upCase);

2. 引用的透明性

一切的运算都在函数中发生,同时每个函数都保持高度的独立性.由于避免全局变量和状态的使用,保证整个函数仅仅与传入的参数有关,传入相同的参数,结果永远都是一样的.

最好的例子就是使用递归,通过每次递归传入不同的参数来执行一系列的运算.整个递归过程除了传入参数外和返回值外,函数不会和外部有任何的交互.这样进一步对函数进行了解耦,体现出了`Scalable(灵活,可升级)`的特点.

函数式编程的好处

1. 代码简洁易读,开发效率高

函数式编程使得代码更加接近自然语言,如果说面向对象编程是名词的聚会,函数式编程则是动词+名词的天下.同时由于基本上全部被封装为独立模块的函数,使得代码的重用变多,代码量变少.

//用java创建map
Map<String, Integer> numberMap = new    HashMap<String, Integer>();
numberMap.put("one", 1);
numberMap.put("two", 2);
numberMap.put("three", 3);
//用Scala创建map
var numberMap = Map("one" -> 1, "two" -> 2, "three" -> 3)
//1 + 2 + 3 * 4用一般编程方法写
var a = 1 + 2 + 3 * 4;
//或者
var a = 1;
var b = 1 + 2;
var c = 3;
var d = c * 4;
var e = b + d;

//而用函数式编程的话
function add(a, b){return a + b};
function multiply(a, b){return a * b};

add(add(1,2),multiply(3,4))
//或者更接近自然语言的
add(1,2).add(multiply(3,4))

2. 代码管理方便,健壮性强

由于使用了函数式编程这种高度封装的风格,每个函数都不互相依赖,都可以看做独立单元,有利于单元测试,debug模块化组合.

3. 为并发编程而生

先看个例子就能明白

var s1 = function F1();
var s2 = function F2();
var s3 = function F3(s2, s1);

由于不存在全局变量和状态,就算将s1, s2两个函数放入两个不同的线程中跑,无论哪个谁先执行,都不会影响到s3的结果,函数式编程根本就不需要考虑死锁.

拓展阅读

函数式编程初探

函数式编程扫盲篇

使用 Scala 编写 Android 应用

Groovy创始人:Java面临终结 Scala将取而代之

Loading Disqus comments...
Table of Contents