中文编程的前世今生

avatar
阿里巴巴 前端委员会智能化小组 @阿里巴巴

文 / 浩知

引子

写这篇文章前,我想先放一张图

image.png
这是 1942 年,人类发明的第一台计算机 ENIAC,它占地 170平方米,按照杭州将近 3 万一平的地价,放它需要花 500 万。这台计算机上如何写代码?它靠的是六位小姐姐通过改变接线来实现。
image.png
格蕾丝·赫柏,不仅是世界上第一位女程序员,还是一名将军,发明 bug 一词并写下千年虫 bug 的女神

第二台 EDVAC 开始,想必大家也有耳闻,用的打孔机。
image.png

其实编程原理很简单,众所周知,我们的电脑无论手机还是 pc,都没有超出冯·诺伊曼架构。底层是由 0 和 1 两个电位构成,我们所有的编程指令,最终都要变成 0 和 1 计算机才能理解。我们知道 CPU 只负责计算,本身不具备智能。你输入一条指令,它就运行一次,然后停下来,等待下一条指令。这些指令都是二进制的,称为操作码(opcode),打孔机输入的就是这些。

一系列操作指令,形成一套指令集(ISC),目前世面上常见的指令集有RISC (简单指令集)和复杂指令集(CISC).
简单地说,简单指令集 就是只规定非常简单的二进制处理器指令,复杂的指令也只是最基本的指令的叠加组合。复杂指令集本身就有一个很庞大的指令集库,内置了很多指令库,只需要调用即可。

前者主要代表有 ARM 架构,后者主要代表有 X86 架构。ARM 架构凭借着内核简单带来的低功耗,在移动和 5G 时代备受欢迎。

经典的分层


当然,对于人类来说,二进制是不可读的,人类又发明了汇编。汇编其实就是二进制指令的助记形式,与指令基本上是一一对应的(有很少的一些抽象),只要把汇编映射成二进制,就可以被 CPU 直接执行,所以它是最底层的低级语言。

image.png

吹牛能直接看二进制的反派第一部就领了便当

计算机的分层架构设计思想,简直是人类智慧的精华。从半导体物理学到云计算,每一层都是对下一层的抽象,上层不需要关心下层的实现,只需要知道自己要给下一层的输入输出是什么。

image.png

在汇编语言之上,出现了对人类更友好的高级语言如 C 语言,它使用近似英语的语法描述代码来表达代码,然后由 gcc 编译器编译成汇编。

以下是一段简单的 C 代码及它在 i7 的 macbook 编译的汇编形式:

int main () {
  return 1 + 2;
}
_main:                                 
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	movl	$0, -4(%rbp)
	movl	$3, %eax
	popq	%rbp
	retq
	.cfi_endproc


我们可以看到,C 比汇编更接近自然语言,而汇编,则是在和指令和寄存器打交道。

中文编程

事实上,世界各国的开发者都进行了基于母语设计编程语言语法的尝试. 有些已经商用且活跃至今。中文圈内比较有名的当属易语言了,还有前阵子产生话题性的文言文编程

很多人听到易语言有些不屑,然而这门语言在一个灰色领域却是 top 级的语言。这个领域就是游戏外挂和黑产木马。国内超过八成以上的外挂和盗号程序来自于易语言。

一门语言的是否能火起来,和进入这个子领域的契机有关。比如 C语言,解决了源代码跨的可移植性问题,C 成为编写操作系统和底层协议的首选语言。Java 赶上企业信息化大潮,强类型、垃圾回收及面向对象的高级抽象,使得架构大型企业级应用不会成为灾难。

js 的流行在于各大浏览器厂商谈不拢,js 成为唯一各浏览器开箱即用的语言,恰好赶上 web2.0 技术兴起,js 具备了不可取代性,之后只能进一步对这门本身设计有缺陷的语言向后兼容扩展,node 的兴起,则是 js 这门语言在向浏览器宿主之外扩张的自然扩张,利益于不错的性能和庞大的用户群体。

Python 则凭借着强大的表现力和数学标准库,在人工智能领域大受欢迎。中文编程,则命中了一个小的群体,这些人不是科班出身,甚至很多没有学历,对英语有天生排斥,有一点小聪明,有强烈意愿的要做成某件事的人。

易语言官方论坛注册人数近百万,能在一个小众领域中做成功,肯定有一些过人之处,虽然易语言的用户群偏离了开发者初衷。

image.png

不吐槽年代感的 win 98 风格,外易语言的 ide 提供了非常友好的可视化布局界面及调试能力。从基础编程能力到几乎涵盖了操作系统的所有库函数的调用。可以开发下载工具,即时通讯、播放器、网站等众类型程序,并且都有官方和第三方模板。ide 的代码编辑部分也做得很用心 ,常被人吐槽的打「如果」快还是 if 快,其实在 ide 里只要输入 rg 的拼音首字母就能快速补全语句块了,整个 ide 体验下来,完全不需要切中文输入法。

然而其实外挂的开发难度并不简单,从 LSP 注入到驱动注入,甚至内核重载,VT 调试,用内联汇编来劫持内存数据。这些根本不是一个连英语单词都拼不来的半吊子能搞定的事。
易语言在外挂界流行,其实还有个外行人不了解的内情:做外挂是在法律的边缘试探,黑客一般不直接出售外挂,而是打包成 dll 非完整的外挂程序形式输送到黑产下游来逃避制裁。易语言说白了核心只做了一件事,调库。

扩展 JS


讲了这些,似乎做为中文编程的一哥易语言也不是多光彩的事,然而,这件事对我们来说却有一些借鉴作用。
易语言做为封闭的商业软件,注定无法成为主流,但我们其实可以简单地为 js 做一些定制来做到类似的事情。以下是一个可以直接正常运行的  js 程序:

var 画布 = 获取画布('#canvas', '2d')
if (存在(画布)) {
  画布.填充颜色('红')
  画布.绘制矩形(10, 10, 55, 50)
}


如果觉得还不够友好,我们可以通过词法分析再简单地扩展一下 js:

var iamotherjs...

```很容易语言
设 画布 为 获取画布('#canvas', '2d')
如果 (存在(画布)): 
  画布.填充颜色('红')
  画布.绘制矩形(10, 10, 50, 50)


以上代码,我们定义一个叫「很容易语言」的文法边界,然后将边界内的字符串通过词法分析拆解成 token,再将 token 生成抽象语法树 AST,再通过 AST 转回普通 JavaScript,我们就可以很容易扩展 js,使其更具备中文表现力,又能依托  js 的完善生态。

更自然的语言


以上的方式,只能降低编程入门的门槛,但还是需要严格的语法界定符,从信息论的角度看,降低熵就要增加人力,这部分复杂度并没有减少和转移。我们需要更自然的语言来描述逻辑,这就是 NLP。

自然语言有 5 个难点,使得计算机处理很困难:

  • 多样性,如「我打了小明」,「小明被我打了」自然语言没有太多规律,但我们能能多种句式理解一致,说明仍有内在规律。
  • 岐义性,如果不联系上下文,缺少环境的约束,语言有很大的歧义性,如「播放美人鱼」,是要看听安徒生童话,还是想看周星驰电影,还是想听周杰伦的歌?
  • 鲁棒性,语言多字少字错字噪音,如比这话句你并不会觉得无发理解。
  • 常识,自然语言有知识依赖,比如开车,到底是开车还是开车?
  • 上下文,对话的上下文,用户身份,用户画像。


对于上小结的代码,我们用一种更说人话的方式表达就是:「在页面 xx 位置画一个红色正方形」。这句话,转成代码,有信息是丢失的。比如,xx 位置,对应 dom 选择器是啥?红色具体色值是啥?正方形多少大小合适?用 canvas 画还是 svg 画?

对于实践,我们可以多增加一些上下文约束来使得样本处理简化:

  • 编程语言:如中文编程语言,它本身是非常结构和严约束的
  • 模板:适用于限定类的场景,挖坑
  • 可视化编排: 比如通过画流程表达逻辑,本质还是强结构约束
  • 专家系统 :需要通过规则,分析到丢失信息,再进一步对话提问

思考


为什么我们需要中文编程?

传统的开发工具链路提效,本质上没有解决任何问题,只是用机器代替了部分人力劳动,而机器是高效且不会出错的。

一个需求的生命周期,从业务方提出想法,到产品经验梳理成 PRD,再到灌输给程序员,逼着程序员上线。这个过程,我们发现,我们都是在讨论同一件事,只是通过不同的方式来描述这件事。需求方通过自然语言,码农通过程序语言。这个过程中,有很大的一部分工作量是双方重复的,只是表达语言不同。

我们是否可以在需求详审的早期,更多地识别出信息缺漏的部分?是否可以找到更多的共性部分,通过更结构化地方式表达,或者更智慧的方式去理解?