函数式编程思想:稍微接触篇

读了几篇关于函数式编程的文章, 来粗浅记录下本身的理解:javascript

对比OOP,FP的核心就是一切都是函数,也就是说”活“的再也不是对象,而是函数。函数本质是x到f(x)的变换,因此FP的元素就两种,一种是函数(”pure function“的概念,表现为命名句柄或表达式,因此独立性->并发性),一种是状态(immutable,由于只要发生变换,就经过函数表现)。 函数的独立性,致使了咱们无法记录函数内部运行的状态,怎么解决呢,把状态放在参数里呗,而后用递归来搞定。html

 

给出msdn里imperative (procedural) programming和 functional programming 的对比:(https://msdn.microsoft.com/en-us/library/bb669144.aspx)java

The functional programming paradigm was explicitly created to support a pure functional approach to problem solving. Functional programming is a form of declarative programming. In contrast, most mainstream languages, including object-oriented programming (OOP) languages such as C#, Visual Basic, C++, and Java –, were designed to primarily support imperative programming.程序员

With an imperative approach, a developer writes code that describes in exacting detail the steps that the computer must take to accomplish the goal. This is sometimes referred to as algorithmic programming. In contrast, a functional approach involves composing the problem as a set of functions to be executed. You define carefully the input to each function, and what each function returns. The following table describes some of the general differences between these two approaches.express

Characteristic编程

Imperative approach并发

Functional approachapp

Programmer focuside

How to perform tasks (algorithms) and how to track changes in state.模块化

What information is desired and what transformations are required.

State changes

Important.

Non-existent.

Order of execution

Important.

Low importance.  

Primary flow control

Loops, conditionals, and function (method) calls.

Function calls, including recursion. 

Primary manipulation unit

Instances of structures or classes.

Functions as first-class objects and data collections.

Although most languages were designed to support a specific programming paradigm, many general languages are flexible enough to support multiple paradigms. For example, most languages that contain function pointers can be used to credibly support functional programming. Furthermore, in C# 3.0 and Visual Basic 9.0, explicit language extensions have been added to support functional programming, including lambda expressions and type inference. LINQ technology is a form of declarative, functional programming.

 

以为有一篇比较适合初学者理解,因此分享下,原文地址:

http://www.ruanyifeng.com/blog/2012/04/functional_programming.html

 

原文: 

 

诞生50多年以后,函数式编程(functional programming)开始得到愈来愈多的关注。

不只最古老的函数式语言Lisp重获青春,并且新的函数式语言层出不穷,好比Erlang、clojure、Scala、F#等等。目前最当红的Python、Ruby、Javascript,对函数式编程的支持都很强,就连老牌的面向对象的Java、面向过程的PHP,都忙不迭地加入对匿名函数的支持。愈来愈多的迹象代表,函数式编程已经再也不是学术界的最爱,开始大踏步地在业界投入实用。

也许继"面向对象编程"以后,"函数式编程"会成为下一个编程的主流范式(paradigm)。将来的程序员恐怕或多或少都必须懂一点。

可是,"函数式编程"看上去比较难,缺少通俗的入门教程,各类介绍文章都充斥着数学符号和专用术语,让人读了如坠云雾。就连最基本的问题"什么是函数式编程",网上都搜不到易懂的回答。

下面是个人"函数式编程"学习笔记,分享出来,与你们一块儿探讨。内容不涉及数学(我也不懂Lambda Calculus),也不涉及高级特性(好比lazy evaluationcurrying),只求尽可能简单通俗地整理和表达,我如今所理解的"函数式编程"以及它的意义。

我主要参考了Slava Akhmechet的"Functional Programming For The Rest of Us"

 

1、定义

简单说,"函数式编程"是一种"编程范式"(programming paradigm),也就是如何编写程序的方法论。

它属于"结构化编程"的一种,主要思想是把运算过程尽可能写成一系列嵌套的函数调用。举例来讲,如今有这样一个数学表达式:

  (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);

这就是函数式编程。

 

2、特色

函数式编程具备五个鲜明的特色。

1. 函数是"第一等公民"

所谓"第一等公民"(first class),指的是函数与其余数据类型同样,处于平等地位,能够赋值给其余变量,也能够做为参数,传入另外一个函数,或者做为别的函数的返回值。

举例来讲,下面代码中的print变量就是一个函数,能够做为另外一个函数的参数。

  var print = function(i){ console.log(i);};

  [1,2,3].forEach(print);

2. 只用"表达式",不用"语句"

"表达式"(expression)是一个单纯的运算过程,老是有返回值;"语句"(statement)是执行某种操做,没有返回值。函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,并且都有返回值。

缘由是函数式编程的开发动机,一开始就是为了处理运算(computation),不考虑系统的读写(I/O)。"语句"属于对系统的读写操做,因此就被排斥在外。

固然,实际应用中,不作I/O是不可能的。所以,编程过程当中,函数式编程只要求把I/O限制到最小,不要有没必要要的读写行为,保持计算过程的单纯性。

3. 没有"反作用"

所谓"反作用"(side effect),指的是函数内部与外部互动(最典型的状况,就是修改全局变量的值),产生运算之外的其余结果。

函数式编程强调没有"反作用",意味着函数要保持独立,全部功能就是返回一个新的值,没有其余行为,尤为是不得修改外部变量的值。

4. 不修改状态

上一点已经提到,函数式编程只是返回新的值,不修改系统变量。所以,不修改变量,也是它的一个重要特色。

在其余类型的语言中,变量每每用来保存"状态"(state)。不修改变量,意味着状态不能保存在变量中。函数式编程使用参数保存状态,最好的例子就是递归。下面的代码是一个将字符串逆序排列的函数,它演示了不一样的参数如何决定了运算所处的"状态"。

  function reverse(string) {

    if(string.length == 0) {

      return string;

    } else {

      return reverse(string.substring(1, string.length)) + string.substring(0, 1);

    }

  }

因为使用了递归,函数式语言的运行速度比较慢,这是它长期不能在业界推广的主要缘由。

5. 引用透明

引用透明(Referential transparency),指的是函数的运行不依赖于外部变量或"状态",只依赖于输入的参数,任什么时候候只要参数相同,引用函数所获得的返回值老是相同的。

有了前面的第三点和第四点,这点是很显然的。其余类型的语言,函数的返回值每每与系统状态有关,不一样的状态之下,返回值是不同的。这就叫"引用不透明",很不利于观察和理解程序的行为。

3、意义

函数式编程到底有什么好处,为何会变得愈来愈流行?

1. 代码简洁,开发快速

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

Paul Graham在《黑客与画家》一书中写道:一样功能的程序,极端状况下,Lisp代码的长度多是C代码的二十分之一。

若是程序员天天所写的代码行数基本相同,这就意味着,"C语言须要一年时间完成开发某个功能,Lisp语言只须要不到三星期。反过来讲,若是某个新功能,Lisp语言完成开发须要三个月,C语言须要写五年。"固然,这样的对比故意夸大了差别,可是"在一个高度竞争的市场中,即便开发速度只相差两三倍,也足以使得你永远处在落后的位置。"

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

(完)

相关文章
相关标签/搜索