文学编程

文学式编程（英語：literate programming）是由高德纳提出的编程方法，希望能用來取代结构化编程范型。 正如高德纳所构想的那样，文学编程范型不同于传统的由计算机强加的编写程序的方式和顺序，而代之以让程序员用他们自己思维内在的逻辑和流程所要求的顺序开发程序。文学编程自由地表达逻辑，而且它用人类日常使用的语言写出来，就好像一篇文章一样，文章里包括用来隐藏抽象的巨集和传统的源代码。文学编程工具用来从文学源文件中获得两种表达方式，一种用于计算机进一步的编译和执行，称作“绕出”（tangled）的代码，一种用于格式化文档，称作从文学源代码中“织出”（woven）。。虽然第一代文学编程工具特定于计算机语言，但后来的工具可以不依赖具体语言，并且存在于比编程语言更高的层次中。 文学程序是用自然语言（比如英语）写出来的对程序逻辑的解释，程序中交织点缀着巨集和传统源代码段。在文学编程的源文件中，巨集很简单，它或与标题类似，或是解决编程问题时用人类语言描述抽象的解释性短语。它把代码段或更低层次的巨集隐藏了起来，且与计算机科学教学时经常用到的，用虛擬碼写的算法相似。这些任意解释的短语成为新的精确的操作符，操作符由程序员在运行过程中创建，组成了在基本编程语言之上的“元语言”。 预处理器用于替换任意层级，说得更准确些是“在'网'和巨集之间建立联系”，用命令"tangle"产生可编译源代码，用命令"weave"产生文档。预处理器还提供了写出巨集的内容的能力和在文学程序源文件中的任何地方增加已创建的巨集的能力，由此不必受传统编程语言强加的那些限制或是打断自己的思路。 根据高德纳本人所说，文学编程为高质量程序而生，因为它强迫程序员显式描述程序背后的思路，让不充分的设计决策无所遁形。高德纳还声称文学编程提供了一流的文档系统，它并非插件，而是随着编程思路的慢慢展现而不断自然发展的过程。产生出来的文档使作者能在以后的任何时间重新找到自己的思路，也能使其他程序员更容易理解程序的建构过程。这与传统文档不同，那里程序员必须和编译器规定的代码顺序写在一起，还必须从代码和注释中重现当时的思路。文学编程的元语言能力也据称[谁？]普遍利于思考，能从更高的层次统观代码，也能增加人的智能可成功保持和处理的概念数量。该概念适用于大规模编程，商业级程序的适用性被 TeX 代码版本证明为文学程序。 文学编程常常被误解为不过是从有源代码和注释的文件中产生格式化文档，或是在代码里写大量的注释。这一误解导致那些文档析出工具，如Perl的Plain Old Documentation（英语：Plain Old Documentation）系统也被称为“文学编程工具”。尽管如此，因为这些工具没有实现隐藏在自然语言巨集系统背后的“抽象概念网”，或是提供把机器规定的源代码顺序变为人类思维更容易理解的顺序的能力，它们不能在高德纳提出的意义下被称作文学编程工具。 一个文学编程的经典例子是标准Unix单词计数程序wc的文学实现。高德纳在他的《文学编程》书中的第12章展示了这个例子的CWEB版本。后来它也为Noweb（英语：Noweb）文学编程工具而重写。这一例子漂亮地阐释了文学编程的基本元素。 创建巨集 下面这个wc的文学编程代码片断展示了在文学编程中用来创建巨集的自然语言的描述性词组有多随意，巨集作为文学编程语言中新的“操作符”，并且隐藏了代码块或其它的巨集。由两个尖括号组成("<<...>>")的标记符号表示巨集，"@"符号在noweb文件中表示一节代码的结束。"<<*>>"符号表示“根”，即最上层节点，文学编程工具要从这里展开巨集组成的网。实际上，扩展的源代码可通过任何节和小节（即标为"<<代码块名>>="的代码）写出来，所以一个文学程序文件可包括多个机器源代码文件。 wc的目的是對多個文件中的行、單詞和字母計數。文件中的行數是......../更多解釋/ 这里是由noweb程序wc.nw定义的文件wc.c的概述： <<*>>= <<包含头文件>> <<定义>> <<全局变量>> <<函数>> <<主程序>> @ 我们必须包含标准输入输出定义，因为我们想发送格式化的输出到stdout和stderr上。 <<包含头文件>>= #include <stdio.h> @ 还要注意，块的分解可以在文字程序文本文件的任何地方进行，不一定按照它们在封闭块中的顺序，而是按照包含整个的解释性文本中反映的逻辑的要求 程序。 作为网的程序 - 巨集不只是节的名字 巨集和标准文档中的“节名”不同。文学编程的巨集能隐藏任何代码块，并且被用于任何低层次的机器语言操作符内，常常在如"if", "while"或 "case"这样的逻辑操作符内。这会在下面这段文学程序wc的代码片断中解释。 这里的代码块做了计数的工作，这正是wc存在的目的，实际上非常容易写。我们察看每一个字母并且如果它是一个单词的开始或结束，则会更改状态。 <<扫描文件>>= while (1) { <<Fill buffer if it is empty; break at end of file>> c = *ptr++; if (c > ' ' && c < 0177) { /* visible ASCII codes */ if (!in_word) { word_count++; in_word = 1; } continue; } if (c == '\n') line_count++; else if (c != ' ' && c != '\t') continue; in_word = 0; /* c is newline, space, or tab */ } @ 实际上，巨集能代表任意的代码块和其它巨集，并且因此比自顶向下或自底向上的代码块或小节更通用。高德纳说当他意识到这一点后，他开始把程序想成不同部分组成的“网”。 人的逻辑顺序，而不是编译器的 在noweb文学程序中，除了可以任意顺序展现代码外，巨集背后的代码块，一旦由"<<...>>="引入，可以在文件后面的任何一个地方通过简单地写"<<代码块名>>="进行扩充并且往里添加更多的内容，如下面这个代码片断所示（"+"为了可读性而被文档格式化器所添加，它并不在代码中）。 The grand totals must be initialized to zero at the beginning of the program. If we made these variables local to main, we would have to do this initialization explicitly; however, C globals are automatically zeroed. (Or rather,``statically zeroed.'' (Get it?) <<Global variables>>+= long tot_word_count, tot_line_count, tot_char_count; /* total number of words, lines, chars */ @ 记录思想碰撞的火花，创建出类拔萃的文档 文学编程的文档作为写程序的一部分而产生。替代注释作为源代码的附注提供，文学编程包含每一层概念的解释，将较低级别的概念推迟到适当的位置，允许了更好的想法交流。 上面文字 wc 的片段显示了程序及其源代码的解释是如何交织在一起的。 这种思想的阐述创造了像文学作品一样的思想流动。Knuth 著名地写了一本“小说”，解释了计算机策略游戏巨洞冒險的代码，完全可读。 第一个发布的文学编程环境是WEB，由高德纳于1981年为他的TeX排版系统而引入。它使用Pascal作为其基础编程语言，使用TeX作为文档排版工具。完整的带注释的 TeX 源代码在高德纳的5卷计算机与排版（英语：Computers and Typesetting）中的TeX: The program里被发表。早在1979年，高德纳私下使用过一个名叫DOC的文学编程系统。他受到皮埃尔•阿诺德•玛尼夫（英语：Pierre-Arnoul de Marneffe）思想的启发。. 免费的 CWEB, 被高德纳和 Silvio Levy编写，是适用于C 和 C++的WEB, 在大部分操作系统上运行，并可以产生TeX和PDF文件. 其它的文学编程概念的实现有noweb和FunnelWeb，它们都是源代码独立的。Noweb以其简单而知名：只有2个文本标记约定和2个调用被需要以使用它，它也允许HTML文本格式化而不是通过TeX系统。FunnelWeb是另一个不依赖于TeX的程序，可以输出HTML文档。它有更复杂的标记（“@”转义任何 FunnelWeb 命令），但有更多弹性选项。 Leo 文本编辑器（英语：Leo (text editor)）是一个大纲编辑器，支持可选的 noweb 和 CWEB 标记。 Leo 的作者混合了两种不同的方法：首先，Leo 是一个大纲编辑器，有助于管理大文本； 其次，Leo 融合了一些文学编程的思想，其纯粹的形式（即 Knuth Web 工具或“noweb”之类的工具使用它的方式）只有在一定程度的创造性和使用编辑器的情况下才有可能 以作者未完全设想的方式（在修改后的 @root 节点中）。 但是，这个和其他扩展（@file 节点）使大纲编程和文本管理成功且容易，并且在某些方面类似于文学编程。 Haskell编程语言对半文学编程有原生支持，其来源于CWEB但用了较简单的实现。如果想要TeX输出，你可以写一个朴素的LaTeX文件，一个给定的环境标记出源代码； LaTeX可以被设置处理那个环境，Haskell 编译器查找正确的标记来确定编译的Haskell语句，像是注释一样舍弃掉TeX文档。但是，像以上描述，这不是高德纳文学编程的本意。Haskell的函数式，模块化 使得语言中直接文学编程更加简单，但它远不如“绕出”可以以任意方式重组的 WEB 工具之一强大。 Sweave - an example of use of the "noweb"-like Literate Programming tool inside the R language for creation of dynamic statistical reports v w x y z Knuth, Donald E. Literate Programming (PDF). The Computer Journal (British Computer Society). 1984, 27 (2): 97–111 [January 4, 2009]. doi:10.1093/comjnl/27.2.97. （原始内容 (PDF)存档于2019-08-19）.  "我感觉自顶向下和自底向上是两种截然相反的方法论：一个更适合分析程序，一个更适合创建程序。但是，使用WEB编程后，我意识到不必在自顶向下和自底向上之间艰难抉择，因为我们最好把程序的结构看作网状而不是树状的。层级结构是存在的，但对于程序来说，最重要的是其结构的关系。一个复杂的软件由多个简单部分和它们之间的简单关系构成。程序员的任务是用人类最易理解的顺序，而不是用像自顶向下或自顶向上之类刻板僵硬的顺序，来描述清楚这些部分和关系。" —高德纳 , Literate Programming 如果有人记得该工具的第一个版本称作WEB，一段好玩的高德纳隐藏其中的文学作品引用不言自明：“啊，自从我们第一次撒谎，就开始编织（weave）一张错综复杂（tangled）的网” - 沃尔特·司各特, in Canto VI, Stanza 17 of Marmion (1808) 写于1513年的一部关于弗洛登战役的史诗。-- 该引文实际上出自1986年5月喬恩·本特利和高德纳发表在"Communications of the ACM, vol 29 num 5 on p.365"的经典栏目“编程珠玑”上的一篇文章的引言中 "WEB的巨集至多允许带一个参数。同样地，我这么做是出于简单考虑，因为我注意到大多数带多参数的应用其实可归纳为单参数的情况。比如说，假如你想定义某个东西……换言之，一个巨集的名字可以作为另一个巨集的参数，这是很有用的。这个特殊的技巧使其成为可能……" —高德纳 , Literate Programming Knuth, Donald E.; Andrew Binstock. Interview with Donald Knuth. April 25, 2008 [January 4, 2009]. （原始内容存档于2021-02-23）. 然而对我来说，文学编程确实是由TeX项目衍生出来的最重要的东西。它不仅让我前所未有地更快地写和维护可靠性更高的程序，而且成为我自20世纪80年代以来的最大的快乐之源——它有时实际上是不可或缺的。我做的其它一些大程序，比如MMIX元模拟器，用我见过的任何一种其它的方法论是无法写出来的。其复杂性让我有限的智能望而却步。没有文学编程，我的整个事业规划就会轰然倒塌。……文学编程是你更上一层楼的必要工具。  引文使用过时参数coauthors (帮助) "我使用WEB时学到的另一令人惊奇的事情是传统编程语言导致我写出了低劣的程序，尽管我还没意识到我在做什么。我原来的想法是WEB仅作为写文档的工具，但我后来发现用WEB写的程序比我用其它语言写的程序都要优秀。" —高德纳 , Literate Programming "因此WEB语言允许人们用"意识流"顺序表达程序。TANGLE is able to scramble everything up into the arrangement that a PASCAL compiler demands. This feature of WEB is perhaps its greatest asset; it makes a WEB-written program much more readable than the same program written purely in PASCAL, even if the latter program is well commented. And the fact that there's no need to be hung up on the question of top-down versus bottom-up, since a programmer can now view a large program as a web, to be explored in a psychologically correct order is perhaps the greatest lesson I have learned from my recent experiences." —高德纳 , Literate Programming Dominus, Mark-Jason. POD is not Literate Programming. Perl.com. March 20, 2000 [January 3, 2009]. （原始内容存档于2009-01-02）.  "我选择WEB作为名字，部分因为它是英语中很少的几个没有用于计算机的三字词语之一。但随着时间流逝，我越来越喜爱这个名字，因为我认为最好把一个复杂的软件确确实实地看成由简单材料以精巧的方式拼出来的一张网。我们通过理解复杂系统的各个简单部分和这些部分与其直接邻居的简单关系来理解复杂系统本身。如果我们用网的概念来表达程序，我们就能用一种自然且圆满地方式强调其结构上的属性。" —高德纳 , Literate Programming Ramsey, Norman. An Example of noweb. May 13, 2008 [January 4, 2009]. （原始内容存档于2021-02-23）.  The game, also known as ADVENT, was originally written by Crowther in about 700 lines of FORTRAN code; Knuth recast it into the WEB idiom. It is available at literateprogramming.com （页面存档备份，存于互联网档案馆） or on Knuth's website 互联网档案馆的存檔，存档日期2008-08-20.. de Marneffe, Pierre Arnoul. Holon Programming - Report PMAR 73-23. University de Liège, Service d'Informatique. December 1973.  Ream, Edward K. Leo's Home Page. September 2, 2008 [January 4, 2009]. （原始内容存档于2006-01-28）.  Hughes, John. Why Functional Programming Matters (PDF). Institutionen för Datavetenskap, Chalmers Tekniska Högskola,. January 9, 2002 [January 4, 2009]. （原始内容存档 (PDF)于2009-07-11）.  Knuth, Donald E. Literate Programming. Stanford, California: Stanford University Center for the Study of Language and Information. 1992. ISBN 978-0937073803.  Guari, Eitan M. TeX & LaTeX: Drawing and Literate Programming. McGraw Hill. 1994. ISBN 0-07-911616-7.  (includes software). Nørmark, Kurt. Literate Programming - Issues and Problems. University of Aalborg. August 13, 1998 [2010-01-03]. （原始内容存档于2011-08-13）.  literateprogamming.com （页面存档备份，存于互联网档案馆） comp.programming.literate FAQ （页面存档备份，存于互联网档案馆） at Internet FAQ Archives Literate Programming newsgroup LiteratePrograms （页面存档备份，存于互联网档案馆） a literate programming wiki. Select （页面存档备份，存于互联网档案馆） A literate programming example using noweb Softpanorama page （页面存档备份，存于互联网档案馆） on literate programming Haskell （页面存档备份，存于互联网档案馆） literate programming Specification of literate programming in the Haskell Report （页面存档备份，存于互联网档案馆） the accepted Haskell standard Noweb — A Simple, Extensible Tool for Literate Programming （页面存档备份，存于互联网档案馆） Lp4all — A Simple Literate Programming Tool with a wiki-like markup syntax （页面存档备份，存于互联网档案馆）