• 编程范式总结


    笔记:

    第一部分:泛型编程,
    讨论了从 C 到 C++ 的泛型编程方法,并系统地总结了编程语言中的类型系统和泛型编程的本质。

    我们可以看到,无论是传统世界,还是编程世界,我们都在干一件事情,什么事呢?那就是通过使用一种更为通用的方式,用另外的话说就是抽象和隔离,让复杂的“世界”变得简单一些。

    然而,要做到抽象,对于 C 语言这样的类型语言来说,首当其冲的就是抽象类型,这就是所谓的——泛型编程。

    程序 = 算法 + 数据

    理想情况下,算法应是和数据结构以及类型无关的,各种特殊的数据类型理应做好自己分内的工作。算法只关心一个标准的实现。

    类型系统

    类型带来的问题就是我们作用于不同类型的代码,虽然长得非常相似,但是由于类型的问题需要根据不同版本写出不同的算法,如果要做到泛型,就需要涉及比较底层的玩法。

    我们需要清楚地知道,无论哪种程序语言,都逃避免不了一个特定的类型系统。哪怕是可随意改变变量类型的动态类型的语言,我们在读代码的过程中也需要脑补某个变量在运行时的类型。

    所以,每个语言都需要一个类型检查系统。

    • 静态类型检查是在编译器进行语义分析时进行的。如果一个语言强制实行类型规则(即通常只允许以不丢失信息为前提的自动类型转换),那么称此处理为强类型,反之称为弱类型。

    • 动态类型检查系统更多的是在运行时期做动态类型标记和相关检查。所以,动态类型的语言必然要给出一堆诸如:is_array()is_int()is_string() 或是 typeof() 这样的运行时类型检查函数。

    范型的本质

    我理解其本质就是 —— 屏蔽掉数据和操作数据的细节,让算法更为通用,让编程者更多地关注算法的结构,而不是在算法中处理不同的数据类型。


    第二部分:函数式编程,
    讲述了函数式编程用到的技术,及其思维方式,并通过 Python 和 Go 修饰器的例子,展示了函数式编程下的代码扩展能力,以及函数的相互和随意拼装带来的好处。

    函数式编程有以下特点。

    特征

    • stateless:函数不维护任何状态。函数式编程的核心精神是 stateless,简而言之就是它不能存在状态,你给我数据我处理完扔出来,里面的数据是不变的。
    • immutable:输入数据是不能动的,动了输入数据就有危险,所以要返回新的数据集。

    优势

    • 没有状态就没有伤害。
    • 并行执行无伤害。
    • Copy-Paste 重构代码无伤害。
    • 函数的执行没有顺序上的问题。

    因为没有状态,所以代码在并行上根本不需要锁(不需要对状态修改的锁),所以可以拼命地并发,反而可以让性能很不错。比如:Erlang 就是其中的代表。

    下面是函数式编程用到的一些技术。

    • first class function(头等函数) :这个技术可以让你的函数就像变量一样来使用。也就是说,你的函数可以像变量一样被创建、修改,并当成变量一样传递、返回,或是在函数中嵌套函数。

    • tail recursion optimization(尾递归优化) : 我们知道递归的害处,那就是如果递归很深的话,stack 受不了,并会导致性能大幅度下降。因此,我们使用尾递归优化技术——每次递归时都会重用 stack,这样能够提升性能。当然,这需要语言或编译器的支持。Python 就不支持。

    • map & reduce :这个技术不用多说了,函数式编程最常见的技术就是对一个集合做 Map 和 Reduce 操作。这比起过程式的语言来说,在代码上要更容易阅读。(传统过程式的语言需要使用 for/while 循环,然后在各种变量中把数据倒过来倒过去的)这个很像 C++ STL 中 foreach、find_if、count_if 等函数的玩法。

    • pipeline(管道):这个技术的意思是,将函数实例成一个一个的 action,然后将一组 action 放到一个数组或是列表中,再把数据传给这个 action list,数据就像一个 pipeline 一样顺序地被各个函数所操作,最终得到我们想要的结果。

    • recursing(递归) :递归最大的好处就简化代码,它可以把一个复杂的问题用很简单的代码描述出来。注意:递归的精髓是描述问题,而这正是函数式编程的精髓。

    • currying(柯里化) :将一个函数的多个参数分解成多个函数, 然后将函数多层封装起来,每层函数都返回一个函数去接收下一个参数,这可以简化函数的多个参数。在 C++ 中,这很像 STL 中的 bind1st 或是 bind2nd。

    • higher order function(高阶函数):所谓高阶函数就是函数当参数,把传入的函数做一个封装,然后返回这个封装函数。现象上就是函数传进传出,就像面向对象对象满天飞一样。这个技术用来做 Decorator 很不错。

    函数式编程关注的是:describe what to do, rather than how to do it。于是,我们把以前的过程式编程范式叫做 Imperative Programming – 指令式编程,而把函数式编程范式叫做 Declarative Programming – 声明式编程。

    函数式语言有三套件,Map、Reduce 和 Filter


    第三部分:面向对象编程,
    讲述与传统的编程思想相反,面向对象设计中的每一个对象都应该能够接受数据、处理数据并将数据传达给其它对象,列举了面向对象编程的优缺点,基于原型的编程范式,以及 Go 语言的委托模式。

    两个面向对象的核心理念。

    • "Program to an ‘interface’, not an ‘implementation’."
      • 使用者不需要知道数据类型、结构、算法的细节。
      • 使用者不需要知道实现细节,只需要知道提供的接口。
      • 利于抽象、封装、动态绑定、多态。
      • 符合面向对象的特质和理念。
    • "Favor ‘object composition’ over ‘class inheritance’."
      • 继承需要给子类暴露一些父类的设计和实现细节。
      • 父类实现的改变会造成子类也需要改变。
      • 我们以为继承主要是为了代码重用,但实际上在子类中需要重新实现很多父类的方法。
      • 继承更多的应该是为了多态。

    第四部分:编程本质和逻辑编程

    • Programs = Algorithms + Data Structures
    • Algorithm = Logic + Control

    Program = Logic + Control + Data Structure

    • Control 是可以标准化的。比如:遍历数据、查找数据、多线程、并发、异步等,都是可以标准化的。

    • 因为 Control 需要处理数据,所以标准化 Control,需要标准化 Data Structure,我们可以通过泛型编程来解决这个事。

    • 而 Control 还要处理用户的业务逻辑,即 Logic。所以,我们可以通过标准化接口 / 协议来实现,我们的 Control 模式可以适配于任何的 Logic。

    上述三点,就是编程范式的本质。

    有效地分离 Logic、Control 和 Data 是写出好程序的关键所在!


    先探讨了编程的本质:逻辑部分才是真正有意义的,控制部分只能影响逻辑部分的效率,然后结合 Prolog 语言介绍了逻辑编程范式,最后对程序世界里的编程范式进行了总结,对比了它们之间的不同。

    • Logic 部分才是真正有意义的(What)
    • Control 部分只是影响 Logic 部分的效率(How)

    程序世界里的编程范式:

  • 相关阅读:
    windows下rabbitmq 延迟插件安装
    java实现生产者和消费者 类比消息中间件
    missing go.sum entry for module providing package <package_name>
    python匹配字符串中某个词的开始位置和结束位置
    Linux中使用Docker安装MongoDB
    pypy下载和安装
    linux配置环境变量
    python替换字符串指定位置上的元素
    Flink:状态管理
    Flink:时间和水位线
  • 原文地址:https://www.cnblogs.com/huilei/p/10535713.html
Copyright © 2020-2023  润新知