介绍
大家好!希望大家都一切顺利。
今年过得真快,转眼就到 Mindshifting May 了。这大概是我最期待的一个月,主要是因为这个月有 Prolog!
希望你们喜欢 Analytical April。参加的人非常多,我觉得它是目前最成功的月份之一。四月里我还和 Simon Peyton Jones 聊了一次,作为 Functional February 的补录访谈。那次访谈真的很棒,我强烈推荐你回看,哪怕只是为了那句绝妙的话:“当命令式编程的石灰岩被侵蚀殆尽,底下显露出来的将是函数式编程的花岗岩。”
好了,进入 Mindshifting May!和往常一样,Erik 和我先给大家简单介绍一下这个月的主题,以及我们要探索的几门语言。
这个月我们足足有六门语言:Ballerina、Pharo、Prolog、Red、Tcl(Tickle)和 Unison。这些语言每一门都和比较“主流”的语言很不一样,所以建议你多试几门,感受一下它们的不同之处。我特别推荐 Prolog,因为它是我这一生中写代码写得最享受的语言之一。Erik 也对 Unison 充满热情,所以那也是一门值得一试的语言。
徽章
要拿到 Mindshifting May 徽章,你需要在五月期间用其中任意一门语言完成任意五道练习。
还有贯穿全年的 12in23 徽章。要拿到它,你需要用这门语言解出五道精选练习。如果你是在五月之后看到这些内容,这一部分在年内任何时候都可以完成,所以你没有错过。挑选这些练习并不容易,因为这些语言彼此差异太大,所以我们选了一些更通用的练习,解起来有趣,也适合探索不同的解法。
- 首字母缩写:把一个短语转换成的首字母缩写
- 等字母词:检查一个短语里是否含有重复的字母
- 罗马数字:把十进制数字转换成罗马数字
- 雨滴:把一个数字转换成雨滴声
- 太空时代:计算一个人在太阳系各行星上的年龄
这些练习以及前几个月的练习都可以在 #12in23 页面上找到。
语言概览
下面我们逐一深入了解一下这些语言。
Prolog:
- 思维方式不同。程序被定义为一组关系。然后你通过合一(模式匹配)来“查询”这个关系数据库,找出答案。非常适合基于规则的系统
- 语法很少,只有一种数据类型(项)和一种语言结构元素(子句)。子句完全由项构成,可以定义事实或规则。
- 非常声明式。不必太关心计算是怎么进行的,而要更关注应该计算什么。很多情况下,这意味着更少的代码
- 专为查询大型搜索空间而设计。支持不同的搜索策略(深度优先、广度优先),并支持自动剪枝
Unison
- Unison 代码里没有版本冲突!Unison 函数知道自己依赖项的哈希值,因此能找到它需要的正确版本代码。
- Unison 支持在本地开发界面和托管仓库中实时浏览代码,所以你总能点进去查看所依赖库的源代码。
- Abilities 是一种以纯函数式方式管理“效果”(例如 IO)的方法
Pharo
- 语法极少,整个语法能写在一张明信片上(只有 6 个保留字!)。消息语法模仿自然语言,有主语、动词和补语(between: 1 and: 2 +)。语义也很简单(例如极其简单的优先级规则)。这让它更容易学习和阅读
- 一旦跨过最初的学习曲线,开发效率就非常高。原因有很多,包括简单的语义和极少的语法,也有后面会提到的 Pharo 一些突出特性
- 能在大多数平台上运行(Windows、macOS、Linux,并支持 ARM),运行在快速的虚拟机(OpenSmalltalk)之上
- 它不只是一个 Smalltalk 实现,而且仍在积极开发中(最新的 Smalltalk 版本是 1980 年的 Smalltalk 80)
- 社区友好
Tcl(读作 “tickle”)
- 语法极少,只有 12 条规则,一张纸就能写下。语义也相对直白。这让程序容易阅读和学习
- 通过协程实现简单的并发,可以让异步代码写起来像同步代码一样
- 内置事件循环,用于网络编程和异步文件 I/O
- 成熟,但仍在演进
Ballerina
- 通过语言内置查询,对 JSON、XML 和表格数据提供类型安全的声明式处理,是一等公民级别的支持
- 灵活的类型,结构化类型(鸭子类型)很常见。封闭类型用于实现子类型,而开放类型则能优雅地处理发送过来的过多数据。用于 HTTP 资源时内置数据绑定和验证
- 内置对常见集成模式和连接器的支持,包括分布式事务、补偿和断路器
- 每个 Ballerina 程序都能被任何 Open Telemetry 工具自动观测,让你完全掌控并看清代码的行为和性能。
- 通过 strand(轻量级线程)实现出色的并发。非阻塞 IO 调用很容易。编译器可以帮助检查 worker 之间的发送和接收调用,避免死锁。不可变性对网络编程也很有利
- 通过联合类型显式处理错误,并用
check语法糖来帮忙
Red
- 轻量。整个工具链下载下来约 1.5 MB,单个可执行文件。
- 可移植。交叉编译容易。生成的二进制文件小,且没有依赖。内存占用低。
- Red 有自己的元语言和数据格式(类似 LISP)。程序可以转换和读取代码。
- 响应式:对象可以互相链接,从而减小程序的体积和复杂度(想想 Excel 表格)
这些语言用在哪些地方?
Prolog:
- 人工智能(IBM 的 Watson)
- (自然)语言处理
- 用于知识库的分布式数据库(TerminusDB)
- 甚至被用来描述 Java 虚拟机的类型规则
Unison
- 用于编写分布式系统
- 通用 Web 服务
- 批处理计算任务
Pharo
- 用于交互式工具
- 应用于差异很大的领域:在线交易平台,以及投资管理的云端工具
- 国防行业的用户界面和交互原型设计
- 用于活动策划的 Web 应用
- 用于探索 API、数据和系统的可塑开发环境工具
Tcl
- 用作胶水代码或嵌入到其他系统中
- 用于 CISCO 路由器的图形界面
- 各种制造系统
- NASA 多次使用它
- 其他大公司还包括 Pixar、Boeing、Intel、NBC 等等。
- Tk 这个窗口工具包已被 perl/python/ruby 等其他“脚本”语言采用。
- Expect 是一个用来自动化交互式 CLI 应用的工具
Ballerina
- 用于云原生应用
- MOSIP 使用它。MOSIP 是一个基础身份平台,帮助政府和其他组织以低成本实现数字身份和基础身份系统。
从编程角度看,这些语言有什么有趣的地方?
Prolog:
- 逻辑编程语言(最早的一批之一),本身就是一种范式(和面向对象、函数式编程一样)
- 动态类型
Unison
- 纯函数式语言
- 静态类型
Pharo
- 面向对象的语言,但属于 Smalltalk 意义上的面向对象。和“常规”面向对象语言不同:没有构造函数,没有类型声明,没有接口,也没有基本类型。
- 动态类型
Tcl
- 多范式:支持面向对象、命令式和函数式风格
- 动态类型
Ballerina
- 多范式:面向对象、函数式和声明式
- 静态类型
Red
- 多范式:命令式、函数式、面向对象、符号式和响应式
- 静态类型
它们各自有哪些突出特性?
Prolog:
- 灵活。许多内置谓词能在多个方向上工作。可以用同一套语法查询和创建数据。有些在其他语言里很棘手的问题,在这里轻而易举
- DCG 就像一个内置的解析器组合子,非常适合解析、生成、补全和检查序列
- CLP 是一种用约束来定义程序的高效方式
Unison
- 代码不是文本,而是(不可变的)数据。代码存储在数据库里,通过 Unison Codebase Manager 访问和更新。文本文件只是把代码放进数据库的一种方式。不可变数据还意味着测试结果可以被缓存,类型检查也只需做一次
- 定义通过哈希值引用,而不是通过名字。这被称为“内容寻址”代码。一个定义的语法树决定它的哈希值。没有版本冲突,重命名也很简单。
- Unison 文档是语言中的一等实体,并且始终与它们所描述的函数保持同步。你可以在文档里嵌入可运行的示例,并确保示例代码能编译通过。
- 非常适合云计算:不需要构建,函数可以即时分发,为 Unison 服务间通信编写编解码器的时间也更少。
Pharo
- 直白的执行模型:一切都是对象,执行完全通过消息发生(消息本身也是对象)。连控制流也是通过消息完成的。这个模型虽然简单,却非常强大。和其他面向对象语言很不一样。
- 你的代码存在于 Pharo 镜像里,而不是文本文件中。Pharo 镜像包含应用程序的整个状态,可以在 Pharo 虚拟机中执行。当你保存工作时,Pharo 会把环境的整个状态保存为镜像文件。这个文件包含所有对象、它们之间的关系以及执行上下文。镜像文件可以分享给别人,也可以加载到不同的机器或平台上。这让开发者能轻松地在项目上协作,或分发用 Pharo 构建的应用程序
- 实时而沉浸,运行时通过 Pharo 专用 IDE 即时获得反馈。可以随时运行和修改程序,甚至在程序运行时也可以!强大的调试器,支持重启方法和随时修复 bug
Tcl
- 直白的类型系统:一切都是字符串。“一切都是字符串”曾是 Tcl 的实现方式。如今在底层,它有一套健壮的类型系统,Tcl 实体(无论是字符串、浮点数、数组还是字典)既有特定类型的表示,也有字符串表示。这大大提升了 Tcl 代码的性能,因为它不再需要在字符串之间来回转换。
- “一切以命令运行”。Tcl 没有内置命令。它自带一套命令“标准库”,其中包括 if 和 while 等。添加新的控制流命令非常简单,比如一个 until 循环。覆盖 Tcl 命令也很容易。
- 由于体积小、语义简单,且以 C 库实现,因此很容易嵌入
Ballerina
- 云原生。内置从 JSON 到用户自定义类型的转换。创建(微)服务的语法极其轻量。服务的并发执行是内置的。开箱即支持 HTTP(1 和 2)、graphql 和 gRPC
- 自动生成工件,把你的代码部署到不同的云上。这些工件可以是 Dockerfile、Docker 镜像、Kubernetes YAML 文件,或者无服务器函数。
- 内置把代码可视化为序列图的功能。非常适合可视化代码流程。甚至可以可视化 HTTP 调用
Red
- 非常适合构建和解析领域特定语言/“方言”(Rebol 的术语)。内置了好几种方言:
- Red/System:一种 C 级别的系统编程语言,编译为原生代码
- Parse:一个强大的 PEG 解析器
- VID:一种简单的 GUI 布局创建方言
- Draw:一种矢量 2D 绘图方言
- Rich-text:一种富文本描述方言
- 易用的 GUI。完全跨平台且原生。支持双向绑定、实时更新、事件,并能访问操作系统的各种功能
五月里应该尝试哪一门(或哪几门)?
这些语言各自都很有意思,所以每一门都有值得推荐的理由。
- 如果你对云计算感兴趣,Ballerina 和 Unison 都是很好的选择。Tcl 也有很棒的并发特性
- 如果你熟悉面向对象编程,但想看看另一种诠释,试试 Pharo
- 如果你想体验一下用一门不依赖文本文件的语言编程是什么感觉,可以试试 Pharo 及其独特而强大的 IDE,或者试试配上 Unison Codebase Manager 的 Unison。
- 如果你喜欢极简,Tcl、Prolog、Pharo 和 Red 的语法都相当少,语义也相对简单
- 如果你想看看范式的有趣融合,Ballerina、Tcl 和 Red 都支持多种不同的范式
- 如果你想尝试一些更不寻常的范式,可以试试 Prolog 的逻辑编程、Red 的响应式编程,以及 Ballerina 的声明式编程
- 如果你喜欢函数式编程,不妨看看 Unison,尤其是它的 Abilities。
- 如果你对元编程感兴趣,Tcl、Prolog、Pharo 和 Red 都提供了很好的支持
当然,如果你有时间,我建议你尝试几门!它们每一门都很独特。挑几门推荐语言,去解同一道练习,看看实现差别有多大。