傻瓜式编程范式,程序员的基本功

feng9exe feng9exe     2022-12-21     665

关键词:

我从数据连续性论文延伸阅读时,在HN thread 论坛 @TuringTest 的发言引用中,意外发现了一篇文章《傻瓜式编程范式:程序员基本功》,由彼得·范·罗伊写于 2009 年,描绘了设计编程语言的操作空间。如果你喜欢这篇文章,可能也会喜欢范·罗伊和哈利迪的书《Concepts, Techniques, and Models of Computer Programming》,因为该文的主要内容正是基于这本书。

本文介绍了所有主要编程范式、它们底层的概念以及它们的关系…我们给出了大约 30 个有用的编程范式的分类和它们的关系。

编程范式是基于数学理论或一组特定原则的方法,每一种范式支持一组概念。范·罗伊信仰多范式编程语言:解决一个编程问题,需要选择正确的概念;解决多个问题,则需要组合分属不同部分的多个概念。况且,许多程序需要解决的问题本来就不止一个。“理论上,一门语言应该以良好的方式支持多种概念,这样程序员就可以在需要时选择合适的概念,不受他人所累。”说得很直观,但我觉得也有潜在缺点:阅读这种语言的源码时,需要精通多种范式,并了解它们是怎么相互影响的。(范·罗伊可能在说“良好的方式”时考虑过如何改正这种缺点:真正的多范式语言应该避免跨范式干扰,而不仅仅是支持一大堆概念)。正如范·罗伊本人在后面讨论状态时所说的:“关键在于选择具有正确概念的范式。概念太少,则程序比较复杂;太多,则推理比较复杂。”

编程语言多如牛毛,编程范式却寥若晨星。但还是有那么一些范式的,本文将介绍 27 种有实际使用场景的范式。

下图(图 2)展示了核心理念。“值得好好学习。”每个框是一种范式;框和框之间的箭头表示从一种范式变成另一种范式时需要增加的概念。

技术图片

(范·罗伊原文的)图 2 主要范式图(点击查看大图

图 2 是根据创造性扩展原则(creative extension principle)组织的:

概念组合成范式并非任意为之。可以用创造性扩展原则来组织它们…在一个给定的范式中,程序可能由于技术原因变得复杂,导致与正在解决的特定问题没有直接关系。这意味着我们需要去发掘新概念了。

最常见的是,需要全局修改(而非局部修改)才能实现单个目标。(说句题外话,针对这种问题我又忍不住想给人安利 AOP(面向切面编程)了!)比如,若我们想要函数可以在任意时刻检测错误,并把控制权转给修正错误的代码,我们就需要有“异常”概念,否则将要影响所有代码。

技术图片

(范·罗伊原文的)图 5 异常概念是如何简化程序的

编程范式有两个关键属性:是否具有(用户)可见的不确定性,以及对状态的支持度。

…如果用户用同一套配置开始执行,结果却不同,就叫做他们见到了不确定性。这非常不可取…我们认为,只有在需要表现不确定性时,才应该让用户能够遇到不确定性。

关于状态,我们对范式如何支持及时存储一系列值感兴趣。状态可以是具名的或无名的、确定的或非确定的、串行的或并行的。并非所有组合都有用!下面的图 3 展示了一些有用的:

技术图片

(范·罗伊原文的)图 3 不同等级的状态支持度

主要范式图(图 2)的横轴就是按照上图中粗线组织的。

最重要的四个编程概念

最重要的四个编程概念是记录、词法范围的闭包、独立性(并发)和具名状态。

记录是若干组数据项(比如结构),可通过索引访问其中的每一项。词法范围的闭包,是把一个过程与其对外部的引用(定义闭包时引用的外部数据)结合起来。你可以创建一个‘工作包(packet of work)’在程序中传递,在之后某个时间才执行。独立性在这里指行为可以独立发生。即,它们可以并发地执行。关于并发,最受欢迎的两种范式是状态共享和消息传递。具名状态指我们可以给一个状态起名字,这是最简单的级别。但对于命名可变的状态,范·罗伊有一个更为深刻和有趣的想法:

在编程里,状态就是一个关于时间的抽象概念。函数式编程就没有时间概念…因为函数不会发生变化。现实世界则不同。在现实世界中,没什么东西像函数那样永恒不变。机体会成长和学习。机体在不同的时候受到相同的刺激,反应通常是不同的。对此,我们在程序里要如何建模?我们得创建一个具有唯一标识(它的名字)的实体模型,它的行为在程序运行过程中还会发生改变。为此,我们在程序里加入了一个抽象的时间概念。这个抽象时间概念只是一个序列,具有唯一名字的时间值的序列。

接着范·罗伊又给了一个建议,我觉得自相矛盾:“最好让具名状态永远可见:应始终提供可以从外部访问该状态的途径。”(当谈及正确性时),又说“具名状态对系统的模块化很重要”(想想《information hiding》)。

数据抽象

数据抽象是根据精确规则来组织数据结构用法的方法,这些精确规则保证了数据结构被正确使用。数据抽象分别有一套内部接口、外部接口和两者间的接口。

数据抽象可以按照两个主要维度进行组织:是否使用具名状态,是否将操作绑定到具有数据的单个实体中。

技术图片

(范·罗伊原文的)图 14 组织数据抽象的 4 种方法

范·罗伊接着讨论了多态和继承(注意,范·罗伊倾向于组合优于继承,但若你必须用继承,请确保遵循替换原则)。

并发

并发的核心问题是不确定性。

若程序的用户碰到不确定性,就会很难处理。用户可见的不确定性有时被称为竞态条件(race condition)…

若禁止不确定性,编写具有独立部分的程序将会受限。但我们能够限制不确定行为的可见程度。有两种选择:定义一种语言,所有不确定性都是不可见的;或把不确定性的可见范围限制在真正需要它的地方。

至少有四种编程模式是并发而又屏蔽了不确定性的(没有竞态条件)。表 2(下方)罗列了它们四个以及消息传递式并发。

并发范式是否存在竞态输入可以是不确定的语言例子
声明式并发 Oz、Alice
约束编程 Gecode、Numerica
函数响应式编程 FrTime、Yampa
离散同步编程 Esterel、Lustre、Signal
消息传递并发 Erlang、E
表 2 四种确定性并发范式和一种非确定性的

声明式并发也称为单调数据流(monotonic dataflow)。程序接收确定性输入并用于计算确定性输出。

函数响应式编程缩写为 FRP(又名“连续同步编程(continuous synchronous programming)”)。我们在其中以函数形式编写程序,但函数参数可以更改,并且会影响输出。

离散同步编程(也称为“响应式(reactive)”),系统等待输入事件,执行内部计算,然后发布输出事件。响应式和函数响应式编程之间的主要区别是,响应式编程是离散的而非连续的。

约束

在约束编程中,我们把要解决的问题表述为约束满足问题(constraint satisfaction problem,缩写为 CSP)…约束编程是所有实际编程范式中“最声明式的”(most declarative)。

在约束编程中,不是写一组要执行的指令,而是对问题建模:将问题表述为一组变量、对变量的约束、以及实现了约束的传播器(propagators)。然后把模型传递给求解器(solver)。

语言设计指南

到这里,我们已经将一些概念和范式匆匆过了一遍,接下来我想完成范·罗伊关于设计编程语言的一些想法。有一类有趣的语言叫“双范式”语言。双范式语言通常用一种范式写小型程序,用另一种范式写大型程序。第二种范式通常用来支持抽象和模块化。比如,在面向对象语言中内置的支持约束编程的求解器。

更一般地说,范·罗伊看到了一个分层语言设计,它有四个核心层,这是一个在众多项目中都自发出现的结构:

常见语言的层次结构有四层:严格的功能核心,然后是声明性并发,然后是异步消息传递,最后是全局具名状态。这种分层结构天然地支持四种范式。

范·罗伊从他的分析中得出四个结论:

  1. 声明式编程是编程语言的核心。
  2. 在可预见的未来,声明式编程将保持其核心地位,因为分布式、安全性和容错是编程语言需要支持的基本主题。
  3. 确定性并发是一种重要的并发形式,不应忽视。这是充分利用多核处理器并行性的妙招。
  4. 用于处理一般并发的正确默认方法是消息传递,而非共享状态。

对于大型软件,范·罗伊认为我们需要采用自给自足的系统设计风格,系统可以自行配置、修复、调整等。系统将组件作为一等实体(由闭包规定),可通过高阶编程来操作。组件间通过传递消息来通信。由具名状态和事务来支持系统配置和维护。除此之外,系统本身应设计为一组联动反馈回路(interlocking feedback loops)。说到这,我想起了《系统思考和因果循环图》。

最后再说一句

每个范式都有它的“灵魂”,只有实际使用该范式才能理解。我们建议你通过在编程中实操来探索范式。

查看英文原文:https://blog.acolyer.org/2019/01/25/programming-paradigms-for-dummies-what-every-programmer-should-know/

 

https://www.infoq.cn/article/mGr_QFSASFQV5mK5OONE

http://hiperc.buffalostate.edu/courses/ACM612-F15/uploads/ACM612/VanRoy-Programming.pdf

极客时间-左耳听风-程序员攻略-软件设计(代码片段)

程序员练级攻略:软件设计编程范式学习编程范式可以让你明白编程的本质和各种语言的编程方式。因此,我推荐以下一些资料,以帮助你系统化地学习和理解。极客时间的《编程范式游记》系列文章,目录如下。编程范式游记... 查看详情

系统复习--编程方式

编程范式(Programmingparadigm)编程范式指我们在编写程序解决问题的思路和视角。计算机编程中存在许多编程范式,如命令式编程、声明式编程、面向对象编程以及结构化编程等等。 命令式编程(Imperative) 强调程序代码... 查看详情

javascript函数式编程

编程范式编程范式是一个由思考问题以及实现问题愿景的工具组成的框架。很多现代语言都是聚范式(或者说多重范式):他们支持很多不同的编程范式,比如面向对象,元程序设计,泛函,面向过程,等等。函数式编程范式函... 查看详情

面对对象式编程的基本特征:

面对对象式编程的基本特征:https://www.cnblogs.com/wahaha02/p/10147639.html介绍不同的编程语言具有不同的抽象原语(如下),有的原语抽象层次低,有的原语抽象层次高。其中函数式、DSL是这几年十分热门的编程语言概念。过程式抽象... 查看详情

函数式编程简介-附入门方法(代码片段)

WHAT?什么是函数式编程?函数式编程是一种编程范式。编程范式又是什么?编程范式是一种解决问题的思路。我们熟悉的命令式编程把程序看作一系列改变状态的指令;而函数式编程把程序看作一系列数学函数映射的组合。编程... 查看详情

函数式编程

编程范式函数式编程是一种编程范式,我们常见的编程范式有命令式编程(Imperativeprogramming),函数式编程,逻辑式编程,常见的面向对象编程是也是一种命令式编程。命令式编程是面向计算机硬件的抽象,有变量(对应着存储... 查看详情

声明式编程范式vs命令式编程范式

编程语言分为两类:声明式、命令。  事实上,除命令式以外的范式统称为声明式。下面有一张图划分。 声明式与命令式编程理念和风格  命令式编程是行动导向(Action-Oriented)的,因而算法是显性而目标是隐性的; ... 查看详情

纯函数式编程

...6-11-2818:46:51【问题描述】:所以,我是一位经验丰富的OOP程序员(主要是C++),现在刚刚开始涉足函数式编程。据我了解,在纯函数范式中,函数不应该有条件,应该尽可能使用柯里化来分解。有人可以为我提供以下示例的“纯... 查看详情

傻瓜函数式编程

傻瓜函数式编程FP说明转载,github.com/justinyhuang2006年6月19日,星期一开篇我们这些码农做事都是很拖拉的。每天例行报到后,先来点咖啡,看看邮件还有RSS订阅的文章。然后翻翻新闻还有那些技术网站上的更新,再过一遍编程论... 查看详情

声明式编程范式初探

声明式编程范式初探语言编程语言可以分成两类:命令式声明式事实上,凡是非命令式的编程都可归为声明式编程。因此,命令式、函数式和逻辑式是最核心的三种范式。为清楚起见,我们用一幅图来表示它们之间的关系。与命... 查看详情

响应式编程是一种异步的声名式的面向数据流的编程范式

响应式编程是一种异步的、声名式的、面向数据流的编程范式。 异步:moand、observeable、handle;声名式:用逻辑表述的形式组织代码;使用函数式编程范式。数据流:将数据视作数据流的形式,并用pipeline的形式做处理。 ... 查看详情

编程范式:响应式编程

 响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。例如,在命令式编程环境中,a:=b+c表示将表达式... 查看详情

三种编程范式

命令式编程(imperative)命令式是关于“howtodo”的,告诉计算机每一个步骤如何执行声明式编程(declarative)声明式是关于“whattodo”的,不关心实现的具体步骤,只告诉想要的结果,由计算机(底层程序)决定如何做(howtodo);比如说,我们... 查看详情

面向对象编程(代码片段)

一、编程范式编程范式即编程的方法论,标识一种编程风格.三大编程范式:1.面向过程编程:面向过程是一种以事件为中心的编程思想,编程的时候把解决问题的步骤分析出来,然后用函数把这些步骤实现,在一步一步的具体步... 查看详情

编程范式——函数式编程入门(代码片段)

该系列会有3篇文章,分别介绍什么是函数式编程、剖析函数式编程库、以及函数式编程在React中的应用,欢迎关注我的blog命令式编程和声明式编程拿泡茶这个事例进行区分命令式编程和声明式编程命令式编程1.烧开水(为第一人... 查看详情

什么是函数式编程(代码片段)

主要参考的是《Java函数式编程》高清华译版本定义函数式编程其实就是编写非故意副作用的程序。课外知识——什么是函数函数简单的说就是从A(定义域)到B(值域)的一个映射过程。当然具体的函数还有各种限制,具体见链接。... 查看详情

掌握面向对象编程本质,彻底掌握oop(代码片段)

面向对象基本概念面向对象是一种编程范式。范式是指一组方法论。编程范式是一组如何组织代码的方法论。编程范式指的是软件工程中的一种方法学。一些主流的编程范式:OOP-面向对象编程世界观:一切皆对象。FP-函数式编... 查看详情

函数式编程(代码片段)

WhatFunctionalProgramming(函数式编程)在概念上和ObjectOrientedProgramming(面向对象编程),ProceduralProgramming(过程化编程)类似,是一种编程范式。与OOP以对象为中心的理念不同,FP将所有计算机的操作视为函数运算,函数是操作的基本单位。函... 查看详情