文學程式設計

文學式程式設計（literate programming）是由高德納提出的程式設計方法，希望能用來取代結構化程式設計範型。

正如高德納所構想的那樣，文學程式設計範型不同於傳統的由計算機強加的編寫程式的方式和順序，而代之以讓程式設計師用他們自己思維內在的邏輯和流程所要求的順序開發程式。文學程式設計自由地表達邏輯，而且它用人類日常使用的語言寫出來，就好像一篇文章一樣，文章裡包括用來隱藏抽象的巨集和傳統的原始碼。文學程式設計工具用來從文學原始檔中獲得兩種表達方式，一種用於計算機進一步的編譯和執行，稱作 “繞出”（tangled）的程式碼，一種用於格式化文件，稱作從文學原始碼中 “織出”（woven）。。雖然第一代文學程式設計工具特定於計算機語言，但後來的工具可以不依賴具體語言，並且存在於比程式語言更高的層次中。

概念

文學程式是用自然語言（比如英語）寫出來的對程式邏輯的解釋，程式中交織點綴著巨集和傳統原始碼段。在文學程式設計的原始檔中，巨集很簡單，它或與標題類似，或是解決程式設計問題時用人類語言描述抽象的解釋性短語。它把程式碼段或更低層次的巨集隱藏了起來，且與計算機科學教學時經常用到的，用虛擬碼寫的演算法相似。這些任意解釋的短語成為新的精確的運算子，運算子由程式設計師在執行過程中建立，組成了在基本程式語言之上的 “元語言”。

預處理器用於替換任意層級，說得更準確些是 “在 ' 網' 和巨集之間建立聯絡”，用命令 "tangle" 產生可編譯原始碼，用命令 "weave" 產生文件。預處理器還提供了寫出巨集的內容的能力和在文學程式原始檔中的任何地方增加已建立的巨集的能力，由此不必受傳統程式語言強加的那些限制或是打斷自己的思路。

1.1 優點

根據高德納本人所說，文學程式設計為高質量程式而生，因為它強迫程式設計師顯式描述程式背後的思路，讓不充分的設計決策無所遁形。高德納還聲稱文學程式設計提供了一流的文件系統，它並非外掛，而是隨著程式設計思路的慢慢展現而不斷自然發展的過程。產生出來的文件使作者能在以後的任何時間重新找到自己的思路，也能使其他程式設計師更容易理解程式的建構過程。這與傳統文件不同，那裡程式設計師必須和編譯器規定的程式碼順序寫在一起，還必須從程式碼和註釋中重現當時的思路。文學程式設計的元語言能力也普遍利於思考，能從更高的層次統觀程式碼，也能增加人的智慧可成功保持和處理的概念數量。該概念適用於大規模程式設計，商業級程式的適用性被 TeX 程式碼版本證明為文學程式。

1.2 誤解

文學程式設計常常被誤解為不過是從有原始碼和註釋的檔案中產生格式化文件，或是在程式碼裡寫大量的註釋。這一誤解導致那些文件析出工具，如 Perl 的系統也被稱為 “文學程式設計工具”。儘管如此，因為這些工具沒有實現隱藏在自然語言巨集系統背後的 “抽象概念網”，或是提供把機器規定的原始碼順序變為人類思維更容易理解的順序的能力，它們不能在高德納提出的意義下被稱作文學程式設計工具。

例子

一個文學程式設計的經典例子是標準 Unix 單詞計數程式 wc 的文學實現。高德納在他的《文學程式設計》書中的第 12 章展示了這個例子的 CWEB 版本。後來它也為文學程式設計工具而重寫。這一例子漂亮地闡釋了文學程式設計的基本元素。

建立巨集

下面這個 wc 的文學程式設計程式碼片斷展示了在文學程式設計中用來建立巨集的自然語言的描述性片語有多隨意，巨集作為文學程式語言中新的 “運算子”，並且隱藏了程式碼塊或其它的巨集。由兩個尖括號組成 (">") 的標記符號表示巨集，"@" 符號在 noweb 檔案中表示一節程式碼的結束。">" 符號表示 “根”，即最上層節點，文學程式設計工具要從這裡展開巨集組成的網。實際上，擴充套件的原始碼可透過任何節和小節（即標為 ">=" 的程式碼）寫出來，所以一個文學程式檔案可包括多個機器原始碼檔案。

wc 的目的是對多個檔案中的行、單詞和字母計數。檔案中的行數是......../ 更多解釋 /

這裡是由 noweb 程式 wc.nw 定義的檔案 wc.c 的概述：

>=

>

>

>

>

>

@

我們必須包含標準輸入輸出定義，因為我們想傳送格式化的輸出到 stdout 和 stderr 上。

>=

include

@

還要注意，塊的分解可以在文字程式文字檔案的任何地方進行，不一定按照它們在封閉塊中的順序，而是按照包含整個的解釋性文字中反映的邏輯的要求 程式。

作為網的程式 - 巨集不只是節的名字

巨集和標準文件中的 “節名” 不同。文學程式設計的巨集能隱藏任何程式碼塊，並且被用於任何低層次的機器語言運算子內，常常在如 "if", "while" 或 "case" 這樣的邏輯運算子內。這會在下面這段文學程式 wc 的程式碼片斷中解釋。

這裡的程式碼塊做了計數的工作，這正是 wc 存在的目的，實際上非常容易寫。我們察看每一個字母並且如果它是一個單詞的開始或結束，則會更改狀態。

>=

while (1) {

>

c = *ptr++;

if (c> ' ' && c

實際上，巨集能代表任意的程式碼塊和其它巨集，並且因此比自頂向下或自底向上的程式碼塊或小節更通用。高德納說當他意識到這一點後，他開始把程式想成不同部分組成的 “網”。

人的邏輯順序，而不是編譯器的

在 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?)

>+=

long totwordcount, totlinecount,

totcharcount;

/ 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 命令），但有更多彈性選項。

是一個大綱編輯器，支援可選的 noweb 和 CWEB 標記。 Leo 的作者混合了兩種不同的方法：首先，Leo 是一個大綱編輯器，有助於管理大文字； 其次，Leo 融合了一些文學程式設計的思想，其純粹的形式（即 Knuth Web 工具或 “noweb” 之類的工具使用它的方式）只有在一定程度的創造性和使用編輯器的情況下才有可能 以作者未完全設想的方式（在修改後的 @root 節點中）。 但是，這個和其他擴充套件（@file 節點）使大綱程式設計和文字管理成功且容易，並且在某些方面類似於文學程式設計。

Haskell 程式語言對半文學程式設計有原生支援，其來源於 CWEB 但用了較簡單的實現。如果想要 TeX 輸出，你可以寫一個樸素的 LaTeX 檔案，一個給定的環境標記出原始碼； LaTeX 可以被設定處理那個環境，Haskell 編譯器查詢正確的標記來確定編譯的 Haskell 語句，像是註釋一樣捨棄掉 TeX 文件。但是，像以上描述，這不是高德納文學程式設計的本意。Haskell 的函式式，模組化 使得語言中直接文學程式設計更加簡單，但它遠不如 “繞出” 可以以任意方式重組的 WEB 工具之一強大。