水管模型这一章,我们不得不回到一个问题,函数式和过程式编程的思路在哪里?我们在这里提供了一个形象的比喻。Procedural--houseobject程序化思维,每个变量变量的符号,函数/进程的代号类似于告诉你房子的名字。对于静态语言,我们可能也只需要可以放在房间里的东西。然后,我们每调用一个函数/过程,就把对应房间里的函数和其他房间里的对象拿出来,按照函数重新排列,结果放到原来的房间或者新的房间里。(注意这个描述其实类似于图灵机。)但是这个房间可能更复杂,我们有时可能会参考其他房间,甚至是另一个房子的房间(其他模块,第三方插件),甚至是天气和社会新闻(环境变量、硬件)来找出每次都能解决问题的逻辑(即函数)。这是“house-object”模型最令人困惑的地方。如果你的天气不好,或者其他房屋条件,你的整理规则可能有很大问题,并且很难归因。我们在001中也介绍过这个问题。函数式——水管和数据流在函数式编程中,我们的模型是编造一系列的水管,而水管就是函数式中的函数。我们的目标是预先建立各种功能水管的管路系统。然后将水(数据/不可变参数)倒入其中,等待结果从管道的另一端流出。如下图所示:stateDiagram-v2[*]-->functionfunction-->[*]compose目前我们能想到的最简单的就是连接水管。比如在做文本处理的时候,我们很可能会有如下操作。这是典型的水管拼接工艺。我们只需要维护分词、小写、删除停用词、词干提取等功能即可。stateDiagram-v2[*]-->分词-->小写转小写-->deletestopwordsdeletestopwords-->stemmingstemming-->[*]当然,我们可以一步一步往水管里倒水,取出后倒入另一根水管中。那不如我们提前把水管串起来。这个操作也称为组合(用符号\(\circ\)表示),数学表达式如下:$$(f\circg)x=f(g(x))$$我们给出一个简单的Python实现:fromfunctoolsimportreducedefcompose(*args):"""composeinmath>>>fromfppy.baseimportcompose>>>compose(lambdax:x+1,lambdax:x**2)(1)>>>4"""returnreduce(lambdaf,g:lambdax:f(g(x)),args,lambdax:x)例如,我们可以将下面的f1、f2、f3串起来:>>>f1=lambdax:x+1>>>f2=lambday:y*2>>>f3=lambdaz:z/3>>>compose(f3,f2,f1)(1)1.33333333333333333>>>h(g(f(1)))1.33333333333333333但是有时候,compose的顺序会让人迷惑,我个人喜欢下面的and_then表达式:defand_then(*args):returnreduce(lambdaf,g:lambdax:g(f(x)),args)我个人比较清楚:>>>and_then(f,g,h)(1)1.3333333333333333但是在具体的实现中,我们其实是把函数作为参数的,这也是表达式“功能tion是函数式编程中的一等公民”。具体来说,各种管道模型(听起来我们是长胡子的法国管道工)我们将在后面的文章中一一展示。
