陈两岁|函数式编程( 二 )
intcnt;voidincrement{cnt++;}
那么 , 函数式的应该怎么写呢?
intincrement(intcnt){returncnt+1;}
你可能会觉得这个例子太普通了 。 是的 , 这个例子就是函数式编程的准则:不依赖于外部的数据 , 而且也不改变外部数据的值 , 而是返回一个新的值给你 。
我们再来看一个简单例子:
definc(x):defincx(y):returnx+yreturnincxinc2=inc(2)inc5=inc(5)printinc2(5)#输出7printinc5(5)#输出10
我们可以看到上面那个例子inc函数返回了另一个函数incx , 于是我们可以用inc函数来构造各种版本的inc函数 , 比如:inc2和inc5 。 这个技术其实就是上面所说的Currying技术 。 从这个技术上 , 你可能体会到函数式编程的理念:把函数当成变量来用 , 关注于描述问题而不是怎么实现 , 这样可以让代码更易读 。
Map&Reduce
在函数式编程中 , 我们不应该用循环迭代的方式 , 我们应该用更为高级的方法 , 如下所示的Python代码
name_len=map(len,[''hao'',''chen'',''coolshell''])printname_len#输出[3,4,9]
你可以看到这样的代码很易读 , 因为 , 这样的代码是在描述要干什么 , 而不是怎么干 。
我们再来看一个Python代码的例子:
deftoUpper(item):returnitem.upperupper_name=map(toUpper,[''hao'',''chen'',''coolshell''])printupper_name#输出['HAO','CHEN','COOLSHELL']
顺便说一下 , 上面的例子个是不是和我们的STL的transform有些像?
#include<iostream>#include<algorithm>#include<string>usingnamespacestd;intmain{strings=''hello'';stringout;transform(s.begin,s.end,back_inserter(out),::toupper);cout<<out<<endl;//输出:HELLO}
在上面Python的那个例子中我们可以看到 , 我们写义了一个函数toUpper , 这个函数没有改变传进来的值 , 只是把传进来的值做个简单的操作 , 然后返回 。 然后 , 我们把其用在map函数中 , 就可以很清楚地描述出我们想要干什么 。 而不会去理解一个在循环中的怎么实现的代码 , 最终在读了很多循环的逻辑后才发现原来是这个或那个意思 。 下面 , 我们看看描述实现方法的过程式编程是怎么玩的(看上去是不是不如函数式的清晰?):
upname=['HAO','CHEN','COOLSHELL']lowname=foriinrange(len(upname)):lowname.append(upname[i].lower)
对于map我们别忘了lambda表达式:你可以简单地理解为这是一个inline的匿名函数 。 下面的lambda表达式相当于:deffunc(x):returnx*x
squares=map(lambdax:x*x,range(9))printsquares#输出[0,1,4,9,16,25,36,49,64]
我们再来看看reduce怎么玩?(下面的lambda表达式中有两个参数 , 也就是说每次从列表中取两个值 , 计算结果后把这个值再放回去 , 下面的表达式相当于:((((1+2)+3)+4)+5))
printreduce(lambdax,y:x+y,[1,2,3,4,5])#输出15
Python中的除了map和reduce外 , 还有一些别的如filter,find,all,any的函数做辅助(其它函数式的语言也有) , 可以让你的代码更简洁 , 更易读 。 我们再来看一个比较复杂的例子:
计算数组中正数的平均值
num=[2,-5,9,7,-2,5,3,1,0,-3,8]positive_num_cnt=0positive_num_sum=0foriinrange(len(num)):ifnum[i]>0:positive_num_cnt+=1positive_num_sum+=num[i]ifpositive_num_cnt>0:average=positive_num_sum/positive_num_cntprintaverage#输出5
如果用函数式编程 , 这个例子可以写成这样:
positive_num=filter(lambdax:x>0,num)average=reduce(lambdax,y:x+y,positive_num)/len(positive_num)
C++11玩的法:
#include<iostream>#include<algorithm>#include<string>usingnamespacestd;intmain{strings=''hello'';stringout;transform(s.begin,s.end,back_inserter(out),::toupper);cout<<out<<endl;//输出:HELLO}