TeX(作为一种编程语言)的语义是否曾经被形式化?


21

在我看来,使用的宏语言可以看作是某种术语重写系统或某种具有按名字调用作用域的编程语言。ŤËX

甚至引擎的现代实现(例如)都以非常直接的方式解释代码,而且我不知道有任何优化执行的尝试(就像现代的优化解释器可以做到的那样)。但是,为类的语言设计正确的优化过程将非常困难,因为宏重新定义可以具有“远距离操作”,并且具有通过按名称调用它们来重新定义宏的能力。X e TŤËXŤXËŤËXŤËX

因此,为实现一种假设的优化解释器在实践中听起来是一个非常困难的问题,但同时也是一个非常有用的问题,因为在数学和科学领域都被广泛使用,并且编译速度慢是该系统的一个已知缺点。请注意,大部分时间都花在解释代码上,而不是在计算实际的排版,尤其是在使用计算量大的包(例如)时。ŤŤËXŤËXtikz

语言的正式语义可能是解决该问题的开始。那么编程语言的语义是否已被形式化了?ŤËX



谢谢!尽管我对将TeX的语法形式化为无上下文语法不感兴趣,但答案很有趣。但是我认为它使水平有些混乱。语法永远无法知道任何一种语言的代码格式是否正确,因为还需要其他检查,例如类型检查或变量查找。但是,大多数语言语法都是用BNF来描述这些方面的。无论如何,我对宏语言的语义更感兴趣,而不是语法。
千兆字节

老实说,答案的作者在其他答案的注释中解决了这个问题,关键是在TeX的情况下,解析涉及评估,因此要知道一段代码是否格式正确,您可能必须评估一段代码。无论如何,这又是关于语法的。
千兆字节

在此博客条目rjlipton.wordpress.com/2011/03/09/tex-is-great-what-is-tex中,Lipton表示Knuth从未正式定义ŤËX
Lamine

好吧,唯一接近您建议的是initex“ precompiler”,基本上,您可以让TeX执行某些操作,然后停止运行,将当前状态保存为“ format”(file.fmt),然后加载蛮快。其实,这是怎么回事乳胶本身是:它在TeX的核心内建这种方式,同样平凡TeX,上下文(尽管这是一个比较复杂),等等
哟,

Answers:


9

(很抱歉,很长的答案指向与网站范围不同的方向:坦率地说,我很惊讶地首先看到这里的问题……。)


TeX设计用于排版,而不是用于编程。因此,当被视为编程语言时,它充其量是“怪异的”。

—唐纳德·努斯(Donald Knuth),数字印刷术,第235页

在过去的几年中,我读了很多关于TeX的早期历史(大约1977年)的书,还读了很多Knuth的著作。我的结论是,当我们谈论“ TeX(作为一种编程语言)”时,已经有些问题了。

如果我们看一下以前写的TeX的早期“设计文档”(请参阅TEXDR.AFTTEX.ONE,发表在Digital Typography上),很显然Knuth正在设计一个主要用于排版计算机编程艺术的系统(他说过(例如,在这里)) (他想到的主要用户是他本人和他的秘书),并且认为,如果对其进行适当修改,它可能会更普遍地有用。为了节省键入的内容,对于重复要做的事情(例如,每次TAOCP需要包含作者的引文时,您都希望垂直移动一定量,设置特定的跳行,选择特定的字体,引用右对齐,选择另一种字体,排版作者的名字...),其中有宏。

您可以猜测其余的。在TeX中,我们遇到的是“偶然的图灵完成”更多)案例,只是它发生在(不幸的)社区(计算机科学家和数学家,DEK本人也要“怪”)社区中太聪明了,不能忽略这一点。(传奇人物迈克尔·斯皮瓦克Michael Spivak)遇到TeX之前从未编程过,但是他对它如此着迷,以至于他最终编写了AMS-TeX,这是当时存在的最复杂的宏集之一。)因为编写了TeX为了能够在大量系统上移植(在当时是很大的事情),在TeX中总是有做所有事情的诱惑。此外,由于他的编译器编写经验,Knuth像编写一个编译器一样编写TeX,并偶尔将其描述为一个。如果在您的输入上运行的程序是“编译器”,那么您肯定在编程,对吗?

此答案中,您可以读到更多有关Knuth不打算在TeX中进行任何编程的知识,以及他如何“只有在大喊大叫之后才能使用TeX的许多编程功能” 。正如我所说,无论他的意图是什么,人们确实开始想出(滥用)TeX宏系统来完成令人惊讶的编程壮举的方法。克努特发现这个迷人的和(除了增加了一些功能集成到TeX的本身)包括其中的几个在附录d“搞鬼” 的TeXbook,但事实证明,尽管名称, “十分之九的例子其中有用于LaTeX的实现”。

让我换一种说法:LaTeX是Leslie Lamport在TeX之上编写的宏系统,它是一个很棒的想法。以语义,结构化,面向人的方式(而不是(Knuth)TeX的面向页面的方式(或如Lamport所说的那样,逻辑而不是可视的))来编写文档是一种很棒的方法。但是,在我看来,至少在今天已经完成的情况下,使用TeX宏而不是使用“适当的”编程语言来实现与LaTeX一样复杂的操作,介于巨大的错误和肆无忌per的行为之间。甚至Knuth都人们不仅扩展TeX程序而不是在TeX宏中执行所有操作而感到震惊

今天,有更好的方法来进行“编程”。您可以使用大多数人的计算机上广泛使用的多种语言中的任何一种来使用外部程序,也可以在Lua中使用LuaTeX和程序(并且比单独使用TeX宏做得更好,因为您可以操纵内部结构并正确级别的算法)。而且,如果您做对了,您可能会拥有比TeX宏中实现的程序更好或更快的程序。

从这个角度来看,使TeX中的程序更快的任务几乎很有趣,并且使我想起了描述另一种“偶然的图灵完整”编程“语言”的论文的最后几句话:汤姆·威登海恩(Tom Wildenhain)可爱的“ 论MS的图灵完整性”去年的PowerPoint视频):

PPTXTM证明了PowerPoint开发的理论可能性,[…]。PowerPoint应用程序优化中也需要完成工作。利用PowerPoint自动缓冲下一张幻灯片的潜力很大,通过仔细放置幻灯片可以大大提高应用程序的性能。

立顿描述轶事是说明性的。TeX不仅不存在形式语义,而且也不大可能存在。对于它来说,它太“奇怪”了,“语言”(正如我希望我已经在上面解释的那样)甚至都不是一种语言。例如,您可能认为您正在将宏作为函数编写,但是在其中引入了单个流水字符(甚至是空格),TeX立即将其视为排版指令。

简而言之:TeX会尽早恢复排版,并且在扩展宏时会勉强地这样做(急于进行其“实际”排版工作),这些扩展本身可以依赖于其中的数百种“状态” TeX的程序(像参数的值\hsize或者\baselineskip,箱子和其它寄存器...的内容),这就是为什么TeX的任何形式语义必然是东西,考虑到程序和它的所有内存的整个状态,直到我们最终以类似“ TeX代码的含义就是TeX所做的事情”之类的形式出现,其形式比TeX程序本身更复杂。


很好,(如果我已经说服您的话)TeX并非旨在作为一种编程语言,并且不能像真正的语言一样工作,没有正式的语义,并且今天有更好的编程方法,但是所有这些都无法帮助您实际的问题/问题是,在实践中,许多打算由TeX处理的文档确实使用了复杂的宏(例如LaTeX和TikZ),令人惊叹的庞然大物相互叠加。我们如何才能使其更快并设计出“优化通道”?

您将无法使用IMO的形式语义到达那里。我最近对此有所考虑,以下是一些初步的想法。

我的印象是,Knuth是1960年代经验丰富的编译器作家之一(这就是为什么他被要求写成《计算机编程艺术》的编译器书),而TeX(在许多方面)都是按照编译器的方式编写的。例如,写于1970年代。从那时起,编译器技术和设计得到了改善,TeX程序也可以如此。可以通过加快速度来完成一些事情:

  • 从本质上讲,TeX的编写就像“解释性例程”一样,其中TeX的“眼睛”和“嘴巴”(其输入例程)将指令传递给其“胃”(其语义例程),并逐一执行。(您可以在TeX程序的第15部分中看到一个列表。)例如,当TeX的眼睛/嘴巴碰到\hfill\hskip在其输入中时,肚子会收到一个“ hskip”命令,该命令会起作用。这类似于当今所谓的字节码解释器,并且在重构TeX程序以显式发出这些字节码/操作码时可能会有所价值,以便我们能够使用现有的(今天更为传统的)编译器技术。或至少缓存它们以避免重做工作。当然有很多挑战:

    • 在“胃”中执行命令通常仍涉及读取输入,即输入例程和语义例程的工作不会在单独的阶段发生。例如,如果给出“ hskip”命令\hskip(而不是说\hfill),它将调用scan_glue以从输入中读取胶水规格,这反过来可能涉及扩展宏等,直到找到足够的胶水标记,将输入堆栈保留在状态大不相同。

    • 诸如eTeX和pdfTeX以及XeTeX和LuaTeX之类的引擎引入了新的命令和原语(实际上,每个人实际上都使用eTeX / pdfTex原语);您还需要支持它们,而不仅仅是原始Knuth的TeX程序中的支持。

  • 我们可以做类似“推测执行”的事情,并行(使用多个内核)处理未来的段落(也许从自然的检查点,如新的节或章开始),跟踪它们使用的所有TeX内部状态(取决于),并抛出如果稍后我们发现前面的段落最终更改了该状态,则将其删除(并重做)。目前,TeX完全按顺序在1个处理器上运行;典型的硬件朝着不同的方向发展,并且有多个内核可用。

  • 更简单的是,我们可以简单地通过输入文件的特定部分来缓存工作(已访问和修改了TeX的状态)。(我们可以在输入级别(扩展所有宏的最终结果)或在组装什么盒的级别,或者一直到程序总状态的级别进行缓存。)例如,内部的内容一个\begin{tikzpicture} … \end{tikzpicture}不太可能像页码计数器那样在很大程度上依赖于TeX状态,因此,当我们重新编译TeX文档时,我们可以简单地重用所有工作-如果我们一直跟踪足够的信息以知道这样做是安全的。(当然,TikZ特别具有将其外部化并包括结果的方法,但是这个想法更笼统。)

  • 我们可以使用技术(例如函数编程中使用的那些技术)来处理带有“空洞”的TeX-例如,现在,当您\ref{foo}在LaTeX中编写以引用(例如将来)节号时,它仅在两个编译阶段有效:首先处理整个文档(所有段落都经过排版,页面上放置浮点等),然后将节号写到辅助文件中,然后第二遍全部处理再次完成该工作,这次实际可用的段号。(这种黑客攻击在当时可能是不可避免的,我知道对运行时间的影响是“只是一个恒定因素”,但是……。)相反,如果我们可以简单地处理带有“漏洞”的文档该怎么办(一个带有未确定内容但有一些估计宽度的框)留给节号,然后在文档处理结束时填充该框?(是的,我们的估计宽度可能会出错,并且段落可能需要重新处理,因此甚至页面也需要重新处理,但是我们可以根据需要执行工作,或者出于速度考虑接受一种允许错误宽度的模式部分编号。)

  • 类似的技术也可以用于TeX文档的交互式编辑:当您编辑段落时,可以“实时”处理该段落,而以后的段落只需沿厨房向下移动即可(例如)。我们知道这是可能的,因为已经存在执行此操作的(商业)TeX实现,例如BaKoMaTeX和Texpad以及以前的Textures。(请参阅BaKoMa-TeX和类似TeXpad的主页上的视频,例如,此视频 -我尝试了后者,但实际上它实在令人难以忍受。

  • 不要小看:向用户展示事物的价值,使TeX更易于调试。现在,用户只能看到他们的TeX输入,却不知道TeX到底在做什么,例如,它在段落的换行或宏扩展(以及哪些宏)上花了多少时间,它在组装什么盒子以及扔掉,哪个包正在写出什么特别的东西,等等。我(也许是乐观的)认为,有些用户希望看到此信息,并会发现它很有用,例如,知道他们正在使用的奇怪的阴影包在后台具有梯度的方程很便宜(几乎不增加处理时间)。通过查看在哪里进行了很多浪费的工作,他们可以将其中的一些扔掉(至少要等到最终的印刷运行之前)。(这有点像将概要分析信息插入程序的编译器或其他工具。)例如,使TeX更加透明和可调试可能会大大提高可用性。(如果我们使用的大多数TeX带有很少的宏,而不是LaTeX或当今大多数用户如何使用它,TeX在其IMO时代就已经非常易于使用和调试了。)

另外,将来的任何工作都应考虑(构建)LuaTeX,这是我们目前对TeX的最佳修改。

所有这些只是闲散的想法(我没有实施任何想法,以了解所需的努力或我们将获得多少提速),但是我希望这可以为您解答问题或为将来的方向提供思路。


我肯定会同意您的观点,即TeX中的编程是受虐狂,但正如您所说,人们还是会这样做,并且正如您所指出的那样,更好的工具所带来的好处将最大程度地落在用户身上。在回答的第二部分中,在提出问题之前,请触摸一下我所想到的许多想法。我可能会补充说,由于\ widthof和类似的东西,循环的终止可能取决于整个排版算法和字体定义。所以XD确实很奇怪
千兆字节(Gigabytes)

这个答案需要大量重写(没有时间写一个简短的答案!),但是非常巧合的是,我刚才在Peter Seibel的《编码员在工作》中碰到了Knuth的这句话,回答了关于形式正确性的问题:“或者例如,TeX是形式上的混乱。它旨在供人类使用,而不是供计算机使用。定义TeX正确意味着什么,将是难以理解的。某些形式语义的方法是如此复杂,以至于没人能理解正确性的定义。”
ShreevatsaR

所以TeX是一种编程语言,但是我不得不插入那些功能。[…]我不喜欢让每种语言都具有通用性,因为它们会以不同的方式通用。[…]我真的在想TeX,因为它包含的程序越多,执行排版的实际任务就越少。当我将素数的计算放入TeX手册中时,我并不认为这是使用TeX的方式。我当时在想:“哦,顺便看看:狗可以站立在后腿上,TeX可以计算素数。”
ShreevatsaR

老实说,我看不出Knuth通过“踢和尖叫”在TeX中添加编程功能的原因。TeX编程不用于执行任意计算,而是围绕问题(通常来自TeX语法本身)进行抽象,以便用户可以更强大地将其用于排版。因此,我不同意Knuth所说的,他投入的程序越多,排版就越少。也许如果他从一开始就接受了对通用可编程性的需求,他可能会想出更好的方法。网络也发生了同样的事情,现在全世界都在JavaScript上运行。
千兆字节

11

不,据我所知,还没有正式形式化您感兴趣的TeX的工作。

(下面是主观和个人评论)。我认为这是一个有趣的想法,您使用它进行优化的动机听起来很合理-另一个相关的问题是,是否可以为其定义字节码格式以加快解释速度。另一方面,这个想法有两个缺点。

首先,我不清楚优化的潜力很大(例如,可以执行哪种程序保存的转换来加快计算速度?),因为语言语义可能与解析密切相关。字符流,因此不太适合优化友好的中间表示形式的设计。

其次,改进TeX解释速度的需求尚未得到充分确立:由于硬件的改进,批处理速度构建的速度一直保持合理。可以接受加速的情况包括复杂的图形程序包(光束演示可能需要花费一些时间来构建),嵌入了丰富计算的程序包(但是另一种语言可能更合适),以及需要快速重建以即时获得用户反馈的用例(但是增量而不是优化可能是重点;形式语义当然也有助于推理增量实现)。

就是说:这听起来像是一个有趣的,具有启发性的话题,但对我而言,尚不清楚从事这项工作的实际理由是否充分。如果有人出于好奇而对这样做感兴趣,那听起来像是一次绝妙的冒险,但是否则,可能会有其他方法来使用相同的技能,而其影响将受到最终用户的追捧。


谢谢。正如您所说,增量编译可能比优化更有趣,尤其是当我们考虑到编辑器目前与语言的集成程度很差时
千兆字节(Gigabytes)

与优化有关的另一个应用程序是自动清除代码,例如删除无用的“ \ expandafter”或类似内容。
千兆字节

“复杂图形包”当然,如果您使用tikz或pgf图形,则始终可以将它们外部化,并在它们不变的情况下在构建上节省大量时间(实际上,这很像增量编译)。
JAB
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.