函数式编程
函数式编程思想有着50多年的历史,最古老的算是Lisp语言了。如今众多语言都在一定程度上支持函数式编程,如Python、Ruby、Javascript,而其他一些语言如Java、PHP都增加了对于匿名函数的支持,可以看到函数编程的思想还很受欢迎。
下面一段话引自知乎,原文地址
函数式编程是一种编程范式,常见的编程范式有命令式编程,函数式编程,逻辑式编程,值得一提的是面向对象编程也是一种命令式编程。命令式编程是面向计算机硬件的抽象,有变量(对应着存储单元),赋值语句(获取及存储指令),表达式(内存引用和算术运算)和控制语句(跳转指令),总之,命令式程序就是一个冯诺依曼机的指令序列。而函数式编程是面向数学的抽象,将计算描述为一种表达式求值,一句话,函数式程序就是一个表达式。
函数式编程中的函数并不是指计算机中的函数,而是指数学中的函数,即自变量的映射,即一个函数的值仅决定于函数参数的值,不依赖其他状态。在函数式语言中,函数作为一等公民,可以在任何地方定义,可以作为函数的参数和返回值,可以对函数进行组合。纯函数式编程语言中的变量也不是命令式编程中的变量,即存储状态的单元,而是代数中的变量,即一个值的名称。变量的值是不可变的,即不允许像命令式编程语言中的那样多次给一个变量赋值。严格意义上的函数式编程意味着不使用可变的变量,赋值,循环和其他命令式控制结构进行编程。
函数式编程的好处
引用透明、没有副作用,用知乎上答主的说法就是
一个好处是,函数既不依赖外部的状态也不修改外部的状态,这使得单元测试和调试更加容易。另一个好处是由于多个线程间不共享状态,因而可以避免发生死锁,可以很好地实现并发。
除此以外,函数式语言还具有以下特性:
- 高阶函数(Higher-order function)
- 偏应用函数(Partially Applied Functions)
- 柯里化(Currying)
- 闭包(Closure)
Python 中的函数式编程
Python中对函数式编程语言的支持主要集中在提供了map(),reduce(),filter()三个函数和lambda算子,让人吃惊的是仅凭这几个函数就几乎可以实现任意的Python程序。
关于这几个函数的使用,参见我的另外一篇博客,上面有对这几个函数的介绍。
下面的内容参考自这个网址
替换条件控制语句
对于下面的条件控制语句1
2
3
4
5
6if condition1:
func1()
elif contidion2:
func2()
else:
func3()
的结构,替换成下面的表达式1
(condition1 and func1()) or (condition2 and func2()) or (func3())
下面是一个例子1
2
3
4
5
6
7
8
9lambda p:p pr=
lambda x:(x==1 and pr("it's one")) or (x==2 and pr("it's two")) or (pr("it's something else")) print_number=
1) print_number(
"it's one"
2) print_number(
"it's two"
3) print_number(
"it's something else"
>>>
可以看到采用这种方式可以实现条件控制的替换。
替换循环控制语句
替换for循环
由于和map函数使用相同,所以可以直接用map函数来实现for循环,看下面的例子1
2
3
4
5
6
7
8
9
10
11
12
13
14lambda x: x**3 cubic=
>>>
>>>
for x in range(5):
cubic(x)
...
0
1
8
27
64
5)) map(cubic,range(
[0, 1, 8, 27, 64]
>>>替换while循环
相较而言,替换while循环稍稍麻烦一些,看下面的例子1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19# statement-based while loop
while <condition>:
<pre-suite>
if <break_condition>:
break
else:
<suite>
# Equivalent FP-style recursive while loop
def while_block():
<pre-suite>
if <break_condition>:
return 1
else:
<suite>
return 0
while_FP = lambda: <condition> and (while_block() or while_FP())
while_FP()
函数式while_FP循环采用了递归的概念。当为true时,进入循环体,执行while_block();若为true时,返回1,while_FP()调用结束;若为false时,返回0,会继续执行or右侧的while_FP(),从而实现递归调用;若始终为false,则会持续递归调用while_FP(),这就实现了while语句中同样的功能。
看一个例子,下面的代码实现输入回显的echo功能,对比一下命令式编程和函数式编程。1
2
3
4
5
6
7
8
9#命令式编程版本
def echo_IMP():
while 1:
x = raw_input("IMP -- ")
print x
if x == 'quit':
break
echo_IMP()
下面是函数式编程版本1
2
3
4
5
6def monadic_print(x):
print x
return x
echo_FP = lambda: monadic_print(raw_input("FP -- "))=='quit' or echo_FP()
echo_FP()
再来看个例子,该例子实现找出笛卡尔积元组集合中元素之积大于25的所有元组。1
2
3
4
5
6
7bigmuls = lambda xs,ys: filter(lambda (x,y):x*y > 25, combine(xs,ys))
combine = lambda xs,ys: map(None, xs*len(ys), dupelms(ys,len(xs)))
dupelms = lambda lst,n: reduce(lambda s,t:s+t, map(lambda l,n=n: [l]*n, lst))
print bigmuls([1,2,3,4],[10,15,3,22])
[(3, 10), (4, 10), (2, 15), (3, 15), (4, 15), (2, 22), (3, 22), (4, 22)]