3 教程(一)——背景知识

  • 2644
  • 9 min

3 教程这个系列的文章其实早已动笔(开始于 2017 年),但一直只挖坑而不填土。作为初学者,错误在所难免,恳请各位不吝赐教。

历史回顾 ​

众所周知,Donald E. Knuth 在排版他的传世巨著 The Art of Computer Programming 时,忍受不了当时的数字排版技术,于是一咬牙,花了近十年开发出了伟大的排版软件 。

然而这个 本身是为 Knuth 自己服务的,普通人用起来会比较吃力。上世纪 80 年代,同样身为计算机科学家的 Leslie Lamport 教授开发出了 (Lamport ),隐藏了一些排版细节,成为了一套结构化的文档语言。Lamport 也是在准备他的著作 The Great American Concurrency Book 时发明了 ;可等有了 ,这本书却懒得动笔了……[1]

1992 年, 2.09 发布,之后 Lamport 便退居二线,开发工作交给由 Frank Mittelbach 领导的 3 团队 负责。顾名思义,这个团队就是要代表 行业的发展要求,代表 界最新技术的前进方向,代表 最广大用户的根本利益。于是他们埋头苦干了两年,搞了个大新闻——推出了  。

「 」这个名字,一看就知道来源于微积分里面的 \varepsilon-\delta 语言。「」比 2 大,但是作为一个无穷小量,离 3 却还有着十万八千里。因此过了二十多年,3 的正式发布依然还是遥遥无期。

  的不足 ​

言归正传,我们现在要来聊一聊   到底有什么不足,以至于非得另起炉灶,建立一个全新的版本。

用户层次 ​

要完成高质量的排版,就需要对格式进行精确地控制。然而,很多时候格式控制却没有提供简单易用的接口,往往需要手动修改内部定义。比如要使脚注中的编号行内居中,就需要这么做:[2]

latex
\makeatletter
\renewcommand\@makefntext[1]{%
  \hspace*{-2em}%
  \parindent 0em%
  \noindent
  \hb@xt@ 1.8em{\hss
    \@thefnmark. }%
  #1}
\makeatother

一个简单的例子尚且如此,稍微复杂一些的就需要使用各种补丁、钩子,以及种种肮脏技巧,显得十分不优雅。

另外的办法就是借用别人造好的轮子,调用各种各样的宏包。后果便是,一旦文章写长了,导言区就会成为宏包集锦,一堆 \usepackage,外加各种奇技淫巧般的设置。

当然,针对这个问题,解决方案似乎已经有现成的。比如 KOMA-Script 或者 memoir 文档类(国内用的人不是很多),它们大致把一些常用功能集中在了一起,用户接口也比较统一。

编程层次 ​

另一方面,  缺乏良好的编程界面,简单的流程控制语句也相当繁琐和低效。更不用提丧心病狂的宏展开:[3]

latex
\def\CTEX@replacecommand#1#2#3{%
  \expandafter\expandafter\expandafter\let\expandafter
    \csname #1#3\expandafter\endcsname
    \csname #2#3\endcsname
  \expandafter\expandafter\expandafter\def\expandafter
    \csname #2#3\expandafter\endcsname
    {\csname #1#3\endcsname}}

而且,很多时候   中的编程是 、带注释的 、不带注释的 的混合,还会从奇奇怪怪的宏包里面弄来奇奇怪怪的东西。命名也常常随意且风骚,最后的结果就是可读性与可维护性很差,搞不好还会遇到各种冲突。

内容 vs 格式 ​

更加重大的问题还在于,  并没有很好地实现内容与格式分离的原则。

刚才提到,Knuth 十年磨一剑最终推出的 ,尽管号称「排版神器」,但作者对字体、字号、对齐,甚至断行分页算法等方方面面都要了解,也只有神人才能驾驭得了。而之后,Lamport 不仅考虑了天才的个人奋斗,而且兼顾了凡人的历史进程。他的 把众多排版细节用「傻瓜式」的命令封装起来,因而一经推出便风靡全球。

所谓「内容与格式分离」,在 的语境中,就是尽量使用带有语义的命令来进行标记,而不是直接规定文本的样式。比如:

  • 通过指明 \documentclass 是 article、report 或 book,即表明这是篇幅较短的文章、篇幅中等的报告,或篇幅较长的书籍。 会据此定义不同的样式(包括章节标题、页眉页脚等),而无需作者操心。
  • 用 \emph 而非 \textit 表示强调,这是因为 \emph 就是强调的意思(emphasize),而 \textit 则只是一种格式声明,尽管标准文档类中二者效果基本一致(嵌套的话会有差别)。
  • 用 \thanks 而非 \footnote 给出作者的额外信息(常用在 \author 中),它会用特殊符号进行标记,以区分于一般的脚注。

这样的好处,一方面使得文章结构明确,条理清晰;另一方面,一旦有修改格式的需求,操作起来也会比较轻松。

然而事情并不总是那么完美的。 的内核很小(latex.ltx 约 8500 行,article.cls 约 600 行,size10.clo 约 200 行),要么缺乏相关功能的支持,要么就是格式写死了没法改。总之,除非完全按照八股文的方式,只要你稍微想做一些格式上的更改,就只有 Google 半天再自己写上一长串啰里啰嗦、不知所云的代码。

时代总是在发展的,Till Tantau 教授在准备他的博士论文答辩时,编写了 beamer 文档类,用以构建幻灯片(为此,他还编写了绘图包 PGF/TikZ,简直令人叹为观止)。就架构而言,beamer 的设计是高度创造性的。它划分了 3 个层次:

  • 幻灯片作者只需要了解 frame、theorem、emph 这些与演示相关的命令或环境,只需选择相应的主题(theme),就可以完成制作;
  • 模板 / 主题设计师,可以用 \setbeamertemplate、 \setbeamercolor、 \setbeamerfont 等命令来设置各成分的格式,但却无需考虑演示文稿的具体内容;
  • 高级设计师(或者 程序员),对于每种语义成分,又可以独立调控,直接操纵具体实现细节。

这种层次化的界面,自然就把用户分成了三类,于是内容编写、格式设计与具体实现就可以彻底分离。

如果熟悉前端技术,会发现这是极其相似的:

  • HTML 负责描述网页内容、标记语义元素;
  • CSS 定义样式,规定相应的 HTML 元素应如何显示;
  • 浏览器端负责网页的最终渲染,即呈现样式。

从某种程度上说,前端技术的爆炸式发展给了 3 相当多的经验。在未来,我们完全有理由相信,HTML/CSS 技术和 技术可以互相兼容。

3 与 expl3 ​

总而言之,  尽管是目前最流行的 格式,却也有着相当大的局限性,而且这种局限性不是小修小补能够解决的,必须另起炉灶,重新搭建一套新的格式——3。

所谓格式,就是对 提供的原语(primitive)进行封装,以方便使用。常见的有 plain 、 以及 Cont。3 就是下一代 格式。当然,鉴于   无可撼动的地位,这套格式也不会被放弃,3 格式只会作为额外的选择。至于 3 什么时候可以真的被做成一个完整的格式文件(.fmt),目前仍是一个未知数。

目前,3 的主要开发工作集中在 expl3 宏包中。expl3 提供了丰富的编程接口,我们之后所要介绍的内容,都是围绕这个宏包进行的。expl3 不仅可以运行在 中,也可以在 plain 和 Cont 中使用。

expl3 是 1992 年推出的,至今已经十多年了。目前,有不少宏包已经开始 expl3,也就是使用 3 语法了。比如:

  • ctex-kit 中的 CTeX、xeCJK、xpinyin、zhnumber 等,当前主要由李清、刘海洋和黄晨成等人开发、维护
  • 3 团队成员 Will Robertson 维护的 fontspec、unicode-math,以及 Joseph Wright 维护的 siunitx
  • 本人所编写的 fduthesis 和 zhlipsum

所有已注册的 3 宏包(其实是模块名)及其有关信息可以在 l3prefixes 中找到。

个人想法 ​

以下纯属个人观点,不保证其准确、客观。

  • 作为标记语言, 火候刚好:HTML 略显冗余并不适合直接拿来写文章(尽管有 Emmet),Markdown 简洁清楚但标记元素过于贫乏。相比之下, 的标记则灵活的多,要长则长,要短则短。
  • 作为编程语言, 实际上非常繁琐,提供可靠、便捷的核心语法及标准库,大概才是 3 当下的主要攻坚目标。
  • 其实 相当于 HTML+CSS+JavaScript,既要负责标记,又要管理样式,还要能自由、灵活地实现各种奇幻需求。这种灵活性固然使得「内容与格式分离」的原则得不到彻底贯彻,但试想,所有的格式修改,哪怕只出现一次,也要额外做一个语义标记,又是否确有必要呢?毕竟,排版的 edge cases 实在太多了。
  • 众所周知, 的流行主要是由于强大的数学公式处理能力,以至于一直有人搞不清 和 MathType、MathJax 等的关系。但就这方面而言,3 本身并不能改变多少(倒是 unicode-math 很可能成为未来的方向)。
  • 相比网页排版有 W3C 和一众厂商的推进,桌面排版也有 Adobe 和微软的巨额投入, 界几乎可以说全凭社区的努力。这显然是杯水车薪的,所以对进度也不必有太多指望。即使 3 最后烂尾,目前的成果(expl3 编程接口)也不会付诸东流。

注释 ​

  1. ^: A Document Preparation System - The Writings of Leslie Lamport
  2. ^李清. 脚注要怎么在行内垂直居中呢?- 知乎
  3. ^2015 年 CTeX 宏集进行了较为彻底的重构,这里给出的代码实际上已经不再使用,但仍然保留在代码库中。参考:刘海洋. 多个 \expandafter 的展开过程是怎样的?- 知乎

参考 ​