陈两岁|函数式编程( 三 )
我们可以看到 , 函数式编程有如下好处:
1)代码更简单了 。
2)数据集 , 操作 , 返回值都放到了一起 。
3)你在读代码的时候 , 没有了循环体 , 于是就可以少了些临时变量 , 以及变量倒来倒去逻辑 。
4)你的代码变成了在描述你要干什么 , 而不是怎么去干 。
最后 , 我们来看一下Map/Reduce这样的函数是怎么来实现的(下面是Javascript代码)
MAP函数
varmap=function(mappingFunction,list){varresult=;forEach(list,function(item){result.push(mappingFunction(item));});returnresult;};
下面是reduce函数的javascript实现
REDUCE函数
functionreduce(actionFunction,list,initial){varaccumulate;vartemp;if(initial){accumulate=initial;}else{accumulate=list.shfit;}temp=list.shift;while(temp){accumulate=actionFunction(accumulate,temp);temp=list.shift;}returnaccumulate;};
DeclarativeProgrammingvsImperativeProgramming
前面提到过多次的函数式编程关注的是:describewhattodo,ratherthanhowtodoit.于是 , 我们把以前的过程式的编程范式叫做ImperativeProgramming–指令式编程 , 而把函数式的这种范式叫做DeclarativeProgramming–声明式编程 。
下面我们看一下相关的示例(本示例来自这篇文章) 。
比如 , 我们有3辆车比赛 , 简单起见 , 我们分别给这3辆车有70%的概率可以往前走一步 , 一共有5次机会 , 我们打出每一次这3辆车的前行状态 。
对于ImperativeProgramming来说 , 代码如下(Python):
fromrandomimportrandomtime=5car_positions=[1,1,1]whiletime:#decreasetimetime-=1print''foriinrange(len(car_positions)):#movecarifrandom>0.3:car_positions[i]+=1#drawcarprint'-'*car_positions[i]
我们可以把这个两重循环变成一些函数模块 , 这样有利于我们更容易地阅读代码:
fromrandomimportrandomdefmove_cars:fori,_inenumerate(car_positions):ifrandom>0.3:car_positions[i]+=1defdraw_car(car_position):print'-'*car_positiondefrun_step_of_race:globaltimetime-=1move_carsdefdraw:print''forcar_positionincar_positions:draw_car(car_position)time=5car_positions=[1,1,1]whiletime:run_step_of_racedraw
上面的代码 , 我们可以从主循环开始 , 我们可以很清楚地看到程序的主干 , 因为我们把程序的逻辑分成了几个函数 , 这样一来 , 我们的代码逻辑也会变得几个小碎片 , 于是我们读代码时要考虑的上下文就少了很多 , 阅读代码也会更容易 。 不像第一个示例 , 如果没有注释和说明 , 你还是需要花些时间理解一下 。 而把代码逻辑封装成了函数后 , 我们就相当于给每个相对独立的程序逻辑取了个名字 , 于是代码成了自解释的 。
但是 , 你会发现 , 封装成函数后 , 这些函数都会依赖于共享的变量来同步其状态 。 于是 , 我们在读代码的过程时 , 每当我们进入到函数里 , 一量读到访问了一个外部的变量 , 我们马上要去查看这个变量的上下文 , 然后还要在大脑里推演这个变量的状态 , 我们才知道程序的真正逻辑 。 也就是说 , 这些函数间必需知道其它函数是怎么修改它们之间的共享变量的 , 所以 , 这些函数是有状态的 。
我们知道 , 有状态并不是一件很好的事情 , 无论是对代码重用 , 还是对代码的并行来说 , 都是有副作用的 。 因此 , 我们要想个方法把这些状态搞掉 , 于是出现了我们的FunctionalProgramming的编程范式 。 下面 , 我们来看看函数式的方式应该怎么写?
fromrandomimportrandomdefmove_cars(car_positions):returnmap(lambdax:x+1ifrandom>0.3elsex,car_positions)defoutput_car(car_position):return'-'*car_positiondefrun_step_of_race(state):return{'time':state['time']-1,'car_positions':move_cars(state['car_positions'])}defdraw(state):print''print'n'.join(map(output_car,state['car_positions']))defrace(state):draw(state)ifstate['time']:race(run_step_of_race(state))race({'time':5,'car_positions':[1,1,1]})