水管模型
这一章,咱们要回到一个问题,到底函数式和过程式的编程思路到底在哪里?咱们这里提供一个形象的比喻。
过程式 – 屋子物件
过程式思维里,每一个可变变量、函数 / 过程指称的符号,相似通知你一个屋子的名字。对一个动态语言来说,咱们可能还须要屋子里只能放什么货色。而后,咱们每一次调用一次函数 / 过程,就是将对对应屋子里的函数取出来,以及其余屋子里的物件取出来,依照函数的形式重新整理,把后果放到原先的屋子或者新的屋子里。(留神这个形容和图灵机其实是相似的。)
然而,这个屋子可能会更简单,咱们可能有时候会参考别的屋子里的状况,甚至另一栋房子里的屋子(其余模块、第三方插件),或者甚至是天气和社会新闻(环境变量、硬件)来盘算每一次整顿物件的逻辑(即函数)。这个是「屋子 - 物件」模型中,最让人困惑的事。如果你天气不好,或者别的屋子的状况有问题,你的整顿物件的规定可能就有很大的问题,而且溯因是艰难的。这个咱们也在 001 中介绍过这个问题。
函数式 – 水管和数据流
在函数式编程中,咱们的模型是假造一些列的水管,水管就是函数式中的函数。咱们的指标就是当时将各种函数水管给架设好管道零碎。而后将水(数据 / 不可变参数)倒入进去,期待水管的另一头流出后果就好了。就像上面的图显示的那样:
stateDiagram-v2
[*] --> function
function --> [*]
compose
咱们到目前为止,能够想到的最简略的就是将水管相连。比方,在做文本处理的时候,咱们很有可能会有以下的操作。这个就是典型的水管拼接的过程,咱们只须要保护 分词 、 变小写 、 删除 stopword、词干化 这几个函数即可。
stateDiagram-v2
[*] --> 分词
分词 --> 变小写
变小写 --> 删除 stopwords
删除 stopwords --> 词干化
词干化 --> [*]
当然,咱们能够一步步把水倒到水管里,取出来再倒到另一个水管。那何不咱们就间接当时帮水管串起来。这个操作也被称为 compose
(用符号 \(\circ\) 示意),数学表述如下:
$$(f \circ g) x = f(g(x))$$
咱们给出一个简略的 Python
实现:
from functools import reduce
def compose(*args):
""" 数学中的 compose
>>> from fppy.base import compose
>>> compose(lambda x: x+1, lambda x: x**2)(1)
>>> 4
"""
return reduce(lambda f, g: lambda x: f(g(x)), args, lambda x: x)
比方咱们就能够把上面的 f1
、f2
、f3
给串起来了:
>>> f1 = lambda x: x + 1
>>> f2 = lambda y: y * 2
>>> f3 = lambda z: z / 3
>>> compose(f3, f2, f1)(1)
1.3333333333333333
>>> h(g(f(1)))
1.3333333333333333
不过有时候,compose
的程序会让人困惑,我集体喜爱上面 and_then
的表述:
def and_then(*args):
return reduce(lambda f, g: lambda x: g(f(x)), args)
对我集体而言这样子会更明确:
>>> and_then(f, g, h)(1)
1.3333333333333333
不过在具体实现里,咱们其实用到了作为参数的函数的概念,这个也是函数式编程中「函数是一等公民」的体现,具体各种水管模式(听起来咱们是长胡子的法国水管工)咱们将在上面的文章中一一展示。