文學式編程(英語:literate programming)是由高德納提出的編程方法,希望能用來取代結構化編程範式。[1]

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

概念

編輯

文學程式是用自然語言(比如英語)寫出來的對程式邏輯的解釋,程式中交織點綴着巨集和傳統原始碼段。在文學編程的原始檔中,巨集很簡單,它或與標題類似,或是解決編程問題時用人類語言描述抽象的解釋性短語。它把代碼段或更低層次的巨集隱藏了起來,且與電腦科學教學時經常用到的,用偽代碼寫的演算法相似。這些任意解釋的短語成為新的精確的運算子,運算子由程式設計師在執行過程中建立,組成了在基本程式語言之上的「元語言」。 預處理器用於替換任意層級,說得更準確些是「在'網'和巨集之間建立聯絡」[4],用命令"tangle"產生可編譯原始碼,用命令"weave"產生文件。預處理器還提供了寫出巨集的內容的能力和在文學程式原始檔中的任何地方增加已建立的巨集的能力,由此不必受傳統程式語言強加的那些限制或是打斷自己的思路。

優點

編輯

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

誤解

編輯

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

例子

編輯

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

建立巨集

下面這個wc的文學編程[10]代碼片斷展示了在文學編程中用來建立巨集的自然語言的描述性詞組有多隨意,巨集作為文學程式語言中新的「運算子」,並且隱藏了代碼塊或其它的巨集。由兩個尖括號組成("<<...>>")的標記符號表示巨集,"@"符號在noweb檔案中表示一節代碼的結束。"<<*>>"符號表示「根」,即最上層節點,文學編程工具要從這裏展開巨集組成的網。實際上,擴充的原始碼可通過任何節和小節(即標為"<<代码块名>>="的代碼)寫出來,所以一個文學程式檔案可包括多個機器原始碼檔案。

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

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

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

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

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

 
这里的代码块做了计数的工作这正是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 */
    }
    @

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

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

在noweb文學程式中,除了可以任意順序展現代碼外,巨集背後的代碼塊,一旦由"<<...>>="引入,可以在檔案後面的任何一個地方通過簡單地寫"<<代码块名>>="進行擴充並且往裏添加更多的內容,如下面這個代碼片斷所示("+"為了可讀性而被文件格式化器所添加,它並不在代碼中)。[10]

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 著名地寫了一本「小說」,解釋了電腦策略遊戲巨洞冒險的代碼,完全可讀。[11]

文學編程工具

編輯

第一個發佈的文學編程環境是WEB,由高德納於1981年為他的TeX排版系統而引入。它使用Pascal作為其基礎程式語言,使用TeX作為文件排版工具。完整的帶註釋的 TeX 原始碼在高德納的5卷電腦與排版英語Computers and Typesetting中的TeX: The program里被發表。早在1979年,高德納私下使用過一個名叫DOC的文學編程系統。他受到皮埃爾•阿諾德•瑪尼夫英語Pierre-Arnoul de Marneffe思想的啟發。[12]. 免費的 CWEB, 被高德納和 Silvio Levy編寫,是適用於CC++的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 節點)使大綱編程和文字管理成功且容易,並且在某些方面類似於文學編程。[13]

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

參見

編輯
  • Sweave - an example of use of the "noweb"-like Literate Programming tool inside the R language for creation of dynamic statistical reports

參考文獻

編輯
  1. ^ 1.0 1.1 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). 
  2. ^

    "我感覺自頂向下和由下而上是兩種截然相反的方法論:一個更適合分析程式,一個更適合建立程式。但是,使用WEB編程後,我意識到不必在自頂向下和由下而上之間艱難抉擇,因為我們最好把程式的結構看作網狀而不是樹狀的。層級結構是存在的,但對於程式來說,最重要的是其結構的關係。一個複雜的軟件由多個簡單部分和它們之間的簡單關係構成。程式設計師的任務是用人類最易理解的順序,而不是用像自頂向下或自頂向上之類刻板僵硬的順序,來描述清楚這些部分和關係。"

    高德納 , Literate Programming[1]

  3. ^ 如果有人記得該工具的第一個版本稱作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"的經典欄目「編程珠璣」上的一篇文章的引言中
  4. ^

    "WEB的巨集至多允許帶一個參數。同樣地,我這麼做是出於簡單考慮,因為我注意到大多數帶多參數的應用其實可歸納為單參數的情況。比如說,假如你想定義某個東西……換言之,一個巨集的名字可以作為另一個巨集的參數,這是很有用的。這個特殊的技巧使其成為可能……"

    高德納 , Literate Programming[1]

  5. ^ Knuth, Donald E.; Andrew Binstock. Interview with Donald Knuth. April 25, 2008 [January 4, 2009]. (原始內容存檔於2021-02-23). 然而對我來說,文學編程確實是由TeX專案衍生出來的最重要的東西。它不僅讓我前所未有地更快地寫和維護可靠性更高的程式,而且成為我自20世紀80年代以來的最大的快樂之源——它有時實際上是不可或缺的。我做的其它一些大程式,比如MMIX元模擬器,用我見過的任何一種其它的方法論是無法寫出來的。其複雜性讓我有限的智能望而卻步。沒有文學編程,我的整個事業規劃就會轟然倒塌。……文學編程是你更上一層樓的必要工具。 
  6. ^

    "我使用WEB時學到的另一令人驚奇的事情是傳統程式語言導致我寫出了低劣的程式,儘管我還沒意識到我在做什麼。我原來的想法是WEB僅作為寫文件的工具,但我後來發現用WEB寫的程式比我用其它語言寫的程式都要優秀。"

    高德納 , Literate Programming[1]

  7. ^

    "因此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[1]

  8. ^ 8.0 8.1 Dominus, Mark-Jason. POD is not Literate Programming. Perl.com. March 20, 2000 [January 3, 2009]. (原始內容存檔於2009-01-02). 
  9. ^

    "我選擇WEB作為名字,部分因為它是英語中很少的幾個沒有用於電腦的三字詞語之一。但隨着時間流逝,我越來越喜愛這個名字,因為我認為最好把一個複雜的軟件確確實實地看成由簡單材料以精巧的方式拼出來的一張網。我們通過理解複雜系統的各個簡單部分和這些部分與其直接鄰居的簡單關係來理解複雜系統本身。如果我們用網的概念來表達程式,我們就能用一種自然且圓滿地方式強調其結構上的屬性。"

    高德納 , Literate Programming[1]

  10. ^ 10.0 10.1 10.2 10.3 Ramsey, Norman. An Example of noweb. May 13, 2008 [January 4, 2009]. (原始內容存檔於2021-02-23). 
  11. ^ 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..
  12. ^ de Marneffe, Pierre Arnoul. Holon Programming - Report PMAR 73-23. University de Liège, Service d'Informatique. December 1973. 
  13. ^ Ream, Edward K. Leo's Home Page. September 2, 2008 [January 4, 2009]. (原始內容存檔於2006-01-28). 
  14. ^ 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). 

延伸閱讀

編輯

外部連結

編輯