文学编程

文学编程（literate programming）是由高德纳提出的编程方法，希望能用来取代结构化编程范式。

正如高德纳所构想的那样，文学编程范式不同于传统的由计算机强加的编写程序的方式和顺序，而代之以让程序员用他们自己思维内在的逻辑和流程所要求的顺序开发程序。文学编程自由地表达逻辑，而且它用人类日常使用的语言写出来，就好像一篇文章一样，文章里包括用来隐藏抽象的宏和传统的源代码。文学编程工具用来从文学源文件中获得两种表达方式，一种用于计算机进一步的编译和执行，称作“绕出”（tangled）的代码，一种用于格式化文档，称作从文学源代码中“织出”（woven）。虽然第一代文学编程工具特定于计算机语言，但后来的工具可以不依赖具体语言，并且存在于比编程语言更高的层次中。

## 概念

文学程序是用自然语言（比如英语）写出来的对程序逻辑的解释，程序中交织点缀着宏和传统源代码段。在文学编程的源文件中，宏很简单，它或与标题类似，或是解决编程问题时用人类语言描述抽象的解释性短语。它把代码段或更低层次的宏隐藏了起来，且与计算机科学教学时经常用到的，用虚拟码写的算法相似。这些任意解释的短语成为新的精确的操作符，操作符由程序员在运行过程中创建，组成了在基本编程语言之上的“元语言”。

预处理器用于替换任意层级，说得更准确些是“在'网'和宏之间建立联系”，用命令"tangle"产生可编译源代码，用命令"weave"产生文档。预处理器还提供了写出宏的内容的能力和在文学程序源文件中的任何地方增加已创建的宏的能力，由此不必受传统编程语言强加的那些限制或是打断自己的思路。

### 优点

根据高德纳本人所说，文学编程为高质量程序而生，因为它强迫程序员显式描述程序背后的思路，让不充分的设计决策无所遁形。高德纳还声称文学编程提供了一流的文档系统，它并非插件，而是随着编程思路的慢慢展现而不断自然发展的过程。产生出来的文档使作者能在以后的任何时间重新找到自己的思路，也能使其他程序员更容易理解程序的建构过程。这与传统文档不同，那里程序员必须和编译器规定的代码顺序写在一起，还必须从代码和注释中重现当时的思路。文学编程的元语言能力也据称普遍利于思考，能从更高的层次统观代码，也能增加人的智能可成功保持和处理的概念数量。该概念适用于大规模编程，商业级程序的适用性被 TeX 代码版本证明为文学程序。

### 误解

文学编程常常被误解为不过是从有源代码和注释的文件中产生格式化文档，或是在代码里写大量的注释。这一误解导致那些文档析出工具，如Perl的Plain Old Documentation系统也被称为“文学编程工具”。尽管如此，因为这些工具没有实现隐藏在自然语言宏系统背后的“抽象概念网”，或是提供把机器规定的源代码顺序变为人类思维更容易理解的顺序的能力，它们不能在高德纳提出的意义下被称作文学编程工具。

## 例子

一个文学编程的经典例子是标准Unix单词计数程序`wc`的文学实现。高德纳在他的《文学编程》书中的第12章展示了这个例子的CWEB版本。后来它也为Noweb文学编程工具而重写。这一例子漂亮地阐释了文学编程的基本元素。

创建宏

下面这个`wc`的文学编程代码片断展示了在文学编程中用来创建宏的自然语言的描述性词组有多随意，宏作为文学编程语言中新的“操作符”，并且隐藏了代码块或其它的宏。由两个尖括号组成("`<<...>>`")的标记符号表示宏，"`@`"符号在noweb文件中表示一节代码的结束。"`<<*>>`"符号表示“根”，即最上层节点，文学编程工具要从这里展开宏组成的网。实际上，扩展的源代码可通过任何节和小节（即标为"`<<代码块名>>=`"的代码）写出来，所以一个文学程序文件可包括多个机器源代码文件。

```c
wc的目的是對多個文件中的行、單詞和字母計數。文件中的行數是......../更多解釋/

这里是由noweb程序wc.nw定义的文件wc.c的概述： 
    <<*>>=
    <<包含头文件>>
    <<定义>>
    <<全局变量>>
    <<函数>>
    <<主程序>>
    @
    
我们必须包含标准输入输出定义，因为我们想发送格式化的输出到stdout和stderr上。
    <<包含头文件>>=
    #include <stdio.h>
    @
```

还要注意，块的分解可以在文字程序文本文件的任何地方进行，不一定按照它们在封闭块中的顺序，而是按照包含整个的解释性文本中反映的逻辑的要求 程序。

作为网的程序 - 宏不只是节的名字

宏和标准文档中的“节名”不同。文学编程的宏能隐藏任何代码块，并且被用于任何低层次的机器语言操作符内，常常在如"`if`", "`while`"或 "`case`"这样的逻辑操作符内。这会在下面这段文学程序`wc`的代码片断中解释。

```c
 
这里的代码块做了计数的工作，这正是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文学程序中，除了可以任意顺序展现代码外，宏背后的代码块，一旦由"`<<...>>=`"引入，可以在文件后面的任何一个地方通过简单地写"`<<代码块名>>=`"进行扩充并且往里添加更多的内容，如下面这个代码片断所示（"+"为了可读性而被文档格式化器所添加，它并不在代码中）。

```c
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卷计算机与排版中的TeX: The program里被发表。早在1979年，高德纳私下使用过一个名叫DOC的文学编程系统。他受到皮埃尔•阿诺德•玛尼夫思想的启发。. 免费的 CWEB, 被高德纳和 Silvio Levy编写，是适用于C 和 C++的WEB, 在大部分操作系统上运行，并可以产生TeX和PDF文件.

其它的文学编程概念的实现有noweb和FunnelWeb，它们都是源代码独立的。Noweb以其简单而知名：只有2个文本标记约定和2个调用被需要以使用它，它也允许HTML文本格式化而不是通过TeX系统。FunnelWeb是另一个不依赖于TeX的程序，可以输出HTML文档。它有更复杂的标记（“@”转义任何 FunnelWeb 命令），但有更多弹性选项。

Leo 文本编辑器是一个大纲编辑器，支持可选的 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

## 外部链接

- 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