乐趣区

关于python:Python函数式编程系列002水管模型和compose

水管模型

这一章,咱们要回到一个问题,到底函数式和过程式的编程思路到底在哪里?咱们这里提供一个形象的比喻。

过程式 – 屋子物件

过程式思维里,每一个可变变量、函数 / 过程指称的符号,相似通知你一个屋子的名字。对一个动态语言来说,咱们可能还须要屋子里只能放什么货色。而后,咱们每一次调用一次函数 / 过程,就是将对对应屋子里的函数取出来,以及其余屋子里的物件取出来,依照函数的形式重新整理,把后果放到原先的屋子或者新的屋子里。(留神这个形容和图灵机其实是相似的。)

然而,这个屋子可能会更简单,咱们可能有时候会参考别的屋子里的状况,甚至另一栋房子里的屋子(其余模块、第三方插件),或者甚至是天气和社会新闻(环境变量、硬件)来盘算每一次整顿物件的逻辑(即函数)。这个是「屋子 - 物件」模型中,最让人困惑的事。如果你天气不好,或者别的屋子的状况有问题,你的整顿物件的规定可能就有很大的问题,而且溯因是艰难的。这个咱们也在 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)

比方咱们就能够把上面的 f1f2f3 给串起来了:

>>> 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

不过在具体实现里,咱们其实用到了作为参数的函数的概念,这个也是函数式编程中「函数是一等公民」的体现,具体各种水管模式(听起来咱们是长胡子的法国水管工)咱们将在上面的文章中一一展示。

退出移动版