函数式编程初窥

  最近在学习Erlang和Python。Erlang是完全的函数式编程语言,Python语言是面向对象的语言,但是它的语法引入了大量的函数式编程思想。越研究越觉得函数式的编程思路可以帮助我们规避很多Bug,所以在这里对函数式编程做一个简要的介绍。分析函数式编程的特点、方法论,使用的技术,以及同面向对象编程的异同。

�1、函数式编程简介

背景

  函数式编程诞生于50多年前。现在越来越多的人开始接受并进行函数式编程的实践。不仅最古老的函数式语言 Lisp 重获青春,而且新的函数式语言层出不穷,比如 Erlang、clojure、Scala、F#等等。目前最当红的Objective-C, Python、Ruby、 Javascript都引入了对函数式编程的支持。就连老牌的面向对象的 Java、面向过程的 PHP, 以及苹果最新的swift语言,都忙不迭地加入匿名函数等机制。

  越来越多的迹象表明,函数式编程已经不再是学术界的最爱,开始大踏步地在业界投入实用。 也许继面向对象编程之后,函数式编程会成为下一个编程的主流范式。

  说到函数式编程编程就不得不说面向对象。面向对象是把一个功能的一组操作和相关数据封装在一个对象里,面向对象是对象满天飞。函数式编程是把一个功能的一个操作和相关数据封装在一起,函数式编程是函数满天飞。函数式编程比面向对象的优势就是粒度更小,生命周期更短。减少bug的有效途径就是减少变量的生命周期,缩小模块的粒度;所以函数式编程更不容易引入bug。

定义

  是一种编程范型,它将计算机运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。函数编程语言最重要的基础是λ演算(lambda calculus)。λ演算中最关键的要素就是函数被当作变量处理,能够参与运算。

价值观

函数式编程强调程序的执行结果比执行过程更重要。关注于描述问题,而不是怎么实现,隐藏实现细节。

化繁为简。利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算。

�你的优秀和我的人生无关,请带着你的趾高气扬滚蛋吧。

 下面是一个输出数组的例子  

shoplist = ['apple','mango','carrot','banana']print'My shopping list is now', shoplist#输出#My shopping list is now ['banana', 'carrot', 'mango', 'rice']

  这样的代码更易读,代码只是描述在干什么,而不是如何做到这点的具体实现。如果是过程式编程,需要一个for循环去描述实现细节。

 函数式编程在解决复杂运算问题时,把一个问题分解为若干子问题,逐步求解。软件或程序的拼装会变得更为简单和直观。使代码更容易理解,方便排查问题,并且具有更好的可维护性和扩展性。

 现在有这样一个数学表达式:

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


你的优秀和我的人生无关,请带着你的趾高气扬滚蛋吧。这个就是函数式编程的准则:函数不受外部变量影响,不依赖于外部变量,也不改变外部变量的值。

  传统的过程式编程:

int count;void increment()

{

    returen count++;

}

  函数式编程:

def increment(count):

  returncount+1;

  函数不访问全局变量,也不改变全局变量。



2、函数式编程特性


    封装、继承、多态是面向对象编程的三大特性。函数式编程也有自己的语言特性。

数据不可变性(immutable data)多有的变量只可以赋值一次,变量不可变,如果想改变变量就创建一个新的变量。

  数据的不可变性保证了程序是无状态的,很多难解的bug往往是由各种复杂的状态引起的。比如发现某些情况下程序运行有问题,是某一个状态引起的,但是这个状态有100种可能性,在1000个地方都有对这个状态进行操作。debug的时候要杀人的心都有了。数据不可变性同时保证了函数没有“副作用”,函数的副作用是指除了返回函数值外,还对主调用函数

函数是第一公民(first class method)函数可以像普通变量一样去使用。函数可以像变量一样被创建,修改,并当成变量一样传递,返回或是在函数中嵌套函数。

引用透明(referential transparency)指的是函数的运行不依赖于外部变量或“状态”,只依赖于输入的参数,任何时候只要参数相同,调用函数所得到的返回值总是相同的。天然适应并发编程,因为调用函数的结果具有一致性,所以根本不需要加锁,也就不存在死锁的问题。

�尾递归化(tail call optimization)因为函数调用要压栈保存现场,递归层次过深的话,压栈过多会产生性能问题。所以引入尾递归优化,每次递归时都会重用栈,提升性能。

     把函数作为参数传递的例子

NSComparisonResult (^cmp)(idobj1,idobj2)  = ^NSComparisonResult(idobj1,id obj2) {

    return [obj1 isEqualToString:obj2];

}

NSArray* items = [@"a",@"c",@"d"];

[items sortedArrayUsingComparator:cmp];

  sortedArrayUsingComparator方法负责排序,需要把比较的规则告诉他,将比较方法作为一个参数传到函数中进行运算。



�3、函数式编程技术(方法论)


�映射化简(map & reduce)函数式编程最常见的技术就是对一个集合做Map和Reduce操作。这比起过程式的语言来说,在代码上要更容易阅读。传统过程式的语言需要使用for/while循环,然后在各种变量中把数据倒过来倒过去的

管道    (pipeline)把一组函数放到一个数组或是列表中,然后把数据传给这个列表,数据就像一个pipeline一样顺序地被各个函数所操作,最终得到我们想要的结果。他的设计哲学就是让每个功能就做一件事,并把这件事做到极致,软件或程序的拼装会变得更为简单和直观。


�递归    (recursing)递归最大的好处就简化代码,他可以把一个复杂的问题用很简单的代码描述出来。递归的精髓是描述问题,而这正是函数式编程的精髓。


柯里化  (currying)把一个函数的多个参数分解成多个函数, 然后把函数多层封装起来,每层函数都返回一个函数去接收下一个参数。


高阶函数(higher order function)把函数当参数,接受一个函数作为参数的函数就叫高阶函数。现象上就是函数传进传出。


  map & reduce

  Python代码:

def toUpper(item)

    return item.upper()print map(tuUpper , [“hellow”,”world”])

  将数组里的所有字符串变为大写,直接使用map,不需要写for循环。最后输出 ["HELLO","WORLD"] 


printreduce(lambdax , y : x + y,[1,2,3,4,5])

  将数组里所有数值进行累加,相当于1+2+3+4+5,输出 15。

  lambda是Python的匿名函数,lambda x,y:x+y相当于def func(x,y):return x+y


管道

  如果有一个需求找出一组数中的所有偶数并对他们求平方,最后求他们的和,可以分解成三个步骤:

1)找偶数

2)求平方

3)累加

def even(nums):

     returnfilter(lambdax: x%2==0, nums)def square(nums):

    returnmap(lambdax: x*x, nums)def  total(nums):

    returnreduce(lambdax,y:x+y,nums)

nums = [1,2,3,4,5,6,7,8,9,10]

pipeline = total(square(even(nums)))

  even方法求偶数,square求他们的平方,total方法将他们加在一起。通过管道的方式把他们串联在一起,一个复杂的处理就完成了。

让每个方法只做一件事,并把这件事做到极致


 递归

  在其他类型的语言中,变量往往用来保存状态。变量不可变,意味着状态不能保存在变量中。函数式编程使用参数保存状态,最好的例子就是递归。

voidfun(constint i)

{

    if(i <10&& i >=0)

    {

        NSLog(@"i:%d", i);

        fun(i +1);

    }

}

  每次状态的变化就是值+1。

  

  柯里化

  柯里化就是一个函数只有一个参数,那如果需要两个参数怎么办,比如两个数相加求和。通过把一个参数封装成函数的方式实现。

def func(a):

    def add(b):

        returna+b

    return add

funcA = func(5)printfuncA(10)

  func函数返回一个add函数,funcA变量就是一个a为5的add函数。print funcA(10)就是向add函数传入10,最后结果就是5+10 输出15。


�4、函数式编程意义


  1、代码简洁,快速开发

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


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

   函数式编程注重干什么而不是怎么干,更容易理解。


  3、方便代码的管理和维护

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

  4、易于进行并发开发

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

�  5、代码热升级

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


最后,其实使用面向对象或者面向方法都不重要,重要的是如何理解其中的价值观和方法论,构造可维护、可扩展、稳定又灵活的程序。不管白猫黑猫抓到老鼠就是好猫。


  参考:

http://en.wikipedia.org/wiki/Functional_programming

http://coolshell.cn/articles/10822.html

http://www.2cto.com/shouce/pythonjc/index.html

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

https://github.com/zwaldowski/BlocksKit

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容