On this page:
5.1 基于Racket编程语言而实现的原因
5.1.1 Racket编程语言特性概览
5.1.2 Racket 编程语言的开发原则
5.1.3 Racket的显著优点
5.2 名语言
5.2.1 语法:S-表达式
5.2.2 汉字造字法:基于其发展出的数据结构名
5.2.3 函数命名规则:基于汉字造字法和汉语组词规范发展出的一种轻量级类型指 示方法
5.2.4 翻译程序
5.2.5 文档程序
5.2.6 扩展库
5.2.7 目录结构
5.2.8 核心库
5.2.9 代码实例展示
8.8

5 实现

本章将阐述如何把汉语和汉字融入进 Lisp的S-表达式的语法中并发挥 出汉字汉语的优势(名语言要如何设计实现)。

5.1 基于Racket编程语言而实现的原因

5.1.1 Racket编程语言特性概览

Racket(原名 PLT Scheme)是个通用、多范型,属于Lisp家族的函数式 程序设计语言,它的设计目之一是为了提供一种用于创造设计与实现其它编程 语言的平台,Racket被用于脚本程序设计、通用程序设计、计算机科学教育和 学术研究等不同领域。

Racket有一个实现平台,包含了执行环境、函数库、即时编译器(JIT compiler)等等,还有提供一个以Racket本身写成的开发环境DrRacket(原 名 DrScheme)。

Racket平台的发行版本是免费且开放源代码的,以GNU宽通用公共许可 证授权发行,所有由社群所编写的扩展和包都会被上传到PLaneT(一个网页包 发布系统)。

基于Racket实现的Scribble可以用来构建HTML或PDF(依赖 LaTeX),Racket官方文档就是基于这个语言来编写的。 Racket从8.0的版本开始,将默认的编译和运行系统从Racket BC改为了Racket CS[matthew21], RacketCS基于Chez Scheme编程语言[dybvig09][dybvig22]的实现,Chez Scheme是一个由R. Kent Dybvig开发的Scheme实现,Chez Scheme是最 快的可用的Scheme实现之一,于1985年首次发布,在2016年5月13日随 着被思科公司收购而变为开源软件。

5.1.2 Racket 编程语言的开发原则

Racket 的开发基于以下原则:
  • 编程语言的目的是表述和解决问题,这一过程通常在特定的情境中发 生,该情境有一定的描述语言,因此Racket应该是能够创制新编程语 言的编程语言;

  • 基于上述的表述问题的方式,问题系统可视为多语言的相互联系的组件 的集合,Racket应当能够提供足够的保护机制,允许实现各种语言的完 26整特性;

  • 与问题解决相关的在语言之外的机制,如项目和资源的管理,也可被 Racket转换为语言构造。

5.1.3 Racket的显著优点

总体来说,Racket的以下特点令其非常适合用于实现汉语编程语言:
  • Racket编程语言的设计初衷就是要提供一种用于创造设计与实现其它编 程语言的平台,其势必已经有了丰富的为实现编程语言而所需的各种特 性;

  • Racket编程语言已经被广泛的应用于了计算机科学教育和学术研究等领 域,这有利于获取学术领域最新的研究成果并有利于新研究成果的传 播;

  • Racket编程语言是Scheme的方言,Scheme是Lisp的方言,Racket 继承并发展了Lisp和Scheme的S-表达式语法,S-表达式的极简语法 使得新实现不需要关注语法的实现,并给汉语留下了极大的语义层面上 的发挥空间;

  • Racket是Scheme语言的实现方言里面函数库最为丰富的实现之一;

  • Racket编程语言的文档API是基于其自身而实现的一个称之为 Scribble的编程语言的,这令汉语编程语言的实现文档可以基于 Scribble语言并与原文档做无缝链接跳转。

5.2 名语言

为叙述方便和代码实现上的方便,上文所述“基于 Lisp的S-表达式而实现 的汉语编程语言”我们将在下文统一称之为“名语言”。

“名”有命名之意,即对编程语言里面的抽象概念在自然语言层面上的赋名 化。

5.2.1 语法:S-表达式

因为是基于Lisp的S-表达式而实现的汉语编程语言,S-表达式的极简语法 使得新实现不需要关注语法的实现,并给汉语留下了极大的语义层面上的发挥 空间,所以名语言的语法采用S-表达式。

相较于现今主流的编程语言,名语言的语法遗传自Lisp编程语言,是极其 简单的,称为S-表达式:
  • 它首先由括号约定执行优先级;

  • 然后由每个括号中的第一个字词表示此括号内容的含义(称为前缀表达 式)。

为方便理解,我们简单的罗列一些示例:

代码释意

名语言代码

1+1+1

(+ 1 1 1)

1+2-3

(- (+ 1 2) 3)

2x(3+(5x4))

(* 2 (+ 3 (* 5 4)))

如果1+1=2,则返回3,否则返回4

( (= (+ 1 1) 2) 3 4)

5.2.2 汉字造字法:基于其发展出的数据结构名

毋庸置疑,数据结构是编程语言的基石。

名语言的数据结构可以直接借用Racket语言的内部数据结构,Racket因为用 于学术研究领域的原因,拥有非常多的数据结构,如:Equality、Strings、 Booleans、Characters、Numbers、SymbolsStrings、Byte、Regular Expressions、 Keywords 、Pairs and Lists、Mutable Pairs and Lists、 Vectors、Stencil Vectors、Boxes、Hash Tables、Sequences andStreams、 Dictionaries、Sets、Procedures 等。

这些数据结构从形式上来看,都是基于Lisp的S-表达式和链表的, 彼此之间高度类似且相互之间存在着演变关系,比如:

名语言发挥了中文汉字表象、归类、属性指示的特长和汉字图形化、抽象化 表意的优势而发展了一套更具系统化和结构化的命名系统:

英文单词名

英文创建函数实例

Racket表示法

中文创建函数实例

中文字符名

pair

(cons 1 2)

'(1 . 2)

( 1 2)

list

(list 1 2 3)

'(1 2 3)

(􏿴 1 2 3)

􏿴

list*

(list* 1 2 3)

'(1 2 . 3)

(􏿫 1 2 3)

􏿫

circular-list

(circular-list 1 2 3)

"#0='(1 2 3 . #0#)"

(􏿮 1 2 3)

􏿮

vector

(vector 1 2 3)

'#(1 2 3)

(􏿲 1 2 3)

􏿲

association list

(list (cons 1 2) (cons 3 4))

'((1 . 2) (3 . 4))

(􏿳 1 2 3 4)

􏿳

hash

(hash 1 2 3 4)

'#hash((1 . 2) (3 . 4))

(􏿱 1 2 3 4)

􏿱

如上表所示,从Racket示例中看Racket内部的数据结构 pair、list、vector、association list、hash会发现,它们形态虽有不同但是 却在形式上存在着关系。实际上这主要是因为它们大多都是链表结构的变形。

中文化的单字命名,突出了数据结构之间的演变关系,并且令代码显得更加简 洁工整。

名语言的如上命名示例,演示了汉语命名Lisp编程语言内部数据结构概念的一种思 维方法:

如果我们把“又”看成是编程中数据的概念抽象的话,通过以上表内容, 我们就可以明白要如何用汉字的造字法来的表达LISP语言里面的 固有概念。并且我们能看到,较之英文,汉字的表达是更能体现出这些抽象的 数据结构概念之间的逻辑关系的。

5.2.3 函数命名规则:基于汉字造字法和汉语组词规范发展出的一种轻量级类型指 示方法

对于Lisp语言,比如Racket语言:
  • 函数在 Racket 中特别的称之为“例程”(Procedure),是其最为重要 的一个概念,函数可以用来处理数据;

  • 此外的类似逻辑处理的部分,有一个称之为“语法”(Syntax)概念来 对代码进行形式转换。

Racket作为一种动态编程语言,在代码的书写中并无类型指代,虽然已经 有了基于Racket语言的扩展类型系统库,称为Typed Racket。

而名语言是依附于动态编程的,除了造字方法来优化Racket编程语言里面已有 的抽象数据概念外,与此同时发挥了汉字造字法的精神和文言文精简化、浓缩化的优点, 对于函数命名,名语言也引入发展了一套通过函数名暗示输入参数类型和输出 参数类型的方法。

对于名语言,中文的单字表意特性更利于构造命名,中文化有利于Lisp代 码更易被读懂的关键就是把函数的命名规范化,给予函数命名一种命名规则。

函数名的命名规则,在名语言的官方API文档上有详细记述, 比如 双和􏿴的例程命名规则。以下是提炼:

总则

规则

解释

示例

单字例程名且带有“亻”偏旁

表示例程入参和出参的数据类型相同(且数据内容也部分相同)

佐、佑、攸

例程名字中包含“/入”

表示例程的入参并非常规数据,而是一个函数例程或是匿名函数

佐/入、攸/入、消/入

例程名字中包含“/以”

用于提示例程的入参数据类型

诗修!/以它段

例程名字中包含“/成”的

用于提示例程的输出结果是某一类型

/成诗、/成词

具体库的规则: 除总命名规则外,对于具体的库,会有额外的规则。比如对于pair和list 的汉化库,另有:

函数名规则

含义

对进出参的影响

单字函数名且字包含上偏旁“㐅”

删除、移走、去掉

仅对数据内容产生影响

单字函数名且字包含左偏旁“亻”

相似者(返回相似之数据)

出参数据与进参数据相比,类型相同且内容类似

单字函数名且字包含右偏旁“阝”

部分一样者(返回部分相同之数据)

出参数据与进参数据相比,类型相同且前者是后者的一部分

词语函数名以“分”结尾或包含“分/”

切分(返回复值数据)

出参数据为复值

词语函数名以“*”结尾或包含“*/”

加强力度

仅对数据内容产生影响

5.2.4 翻译程序

因为语法和数据结构是和Racket语言相同的,名语言将会利用Racket语 言的内部特性建立一个翻译层程序,将中文命名转译为Racket语言。

又因为Racket语言拥有非常良好的模块关系,名语言可以针对Racket语 言的标准库、扩展库来进行中英文的翻译映射。

另又因Racket语言的函数编程特性,翻译可以被轻松的作为扩展库而被重 新引入进Racket语言并被使用。

5.2.5 文档程序

因为翻译程序的设计,名语言内部必然是存在一个个中英文映射表的,又因 Racket语言的编写文档所基于的Scribble语言本质上是一个Racket语言的 库,因此名语言可以基于Scribble语言实现并和Racket语言的官方文档进行 无缝衔接跳转,以利于名语言文档的查看和溯源。

5.2.6 扩展库

因为Racket语言实质上是Scheme语言的方言,Scheme遵从一种极简哲 学,所有的代码可以回归到最基础的几个函数定义上,这为名语言的汉化提供 了极大便利:
  • 在不完全汉化的前提下,名语言可以作为函数库被引入Racket部分的 使用;

  • 在不完全汉化的前提下,可以基于名语言来写自身的扩展库,只要扩展 库所使用的Racket库是已经汉化了的;

  • Racket遵从Scheme的极间原则,此原则为将来名语言在底层上摆脱 Racket甚至Scheme提供了条件:当名语言完成Racket和Scheme编 程语言全部的编程概念本地化后,条件即成熟。

5.2.7 目录结构

目录

解释

/*

名语言核心库

mapping/*

中英文映射表(按库结构设子目录)

mapping/racket/*Racket

库的中英文映射表(按库结构设子目录)

racket/*

Raket库的名化库(会自动从中英文映射表中提取翻译)

private/scribble-styles/*

字体以及HTML文档的样式代码

scribble/*

生成 HTML文档的原始代码(会自动从中英文映射表中提取翻译)

doc/*

scribble源代码所生成的 HTML文档(可使用浏览器打开文件以阅读文档)

5.2.8 核心库

名语言的核心库是 名语言的核心代码,主要包含:
  • ming/core:用于为名语言名化(汉化)一个Racket库的,核心为一个用Racket编程语言实现的称之为mingize的函数。

  • ming/scribble:用来从名语言的翻译表中生成翻译文档的,核心分别为用Racket语言实现的defchinesize和defmapping函数。

  • mapping-lang:名语言为了借用Racket的标准库,需要做大量的翻译。又因翻译文件重在数据,其代码逻辑比较简单,故此另外实现了一个简单的模板用以编写翻译映射表。

5.2.9 代码实例展示

名语言的官方API文档中有详细说明,这里不再赘述。