1978 年 ACM 圖靈獎演講

1978 年 ACM 圖靈獎由獎項委員會主席 Walter Carlson 於 12 月 4 日在華盛頓特區舉行的 ACM 年會上頒發給 Robert W. Floyd。

在進行評選時,通用技術成就獎小組委員會(原圖靈獎小組委員會)引用了對 Floyd 教授的讚譽,因為他「協助創立了以下重要的電腦科學子領域:分析理論 (theory of parsing)、程式語言語義 (semantics of programming languages)、自動程式驗證 (automatic program verification)、自動程式合成 (automatic program synthesis) 和演算法分析 (analysis of algorithms)。」

從 University of Chicago 分別於 1953 年和 1958 年獲得文學學士和理學學士學位的 Floyd 教授,是一位自學成才的電腦科學家。他對計算的研究始於 1956 年,當時他作為 IBM 650 的夜間操作員,在載入卡片儲存槽的空檔找到了學習程式設計的時間。

Floyd 實作了最早的 Algol 60 編譯器之一,於 1962 年完成了這項專案的工作。在此過程中,他在編譯器最佳化方面做了一些早期工作。隨後,在 1965 年之前的幾年裡,Floyd 將程式語言的分析系統化。為此,他創立了先行分析法 (precedence method)、有界上下文分析法 (bounded context method) 和產生式語言分析法 (production language method) 等分析方法。

1966 年,Floyd 教授提出了一種數學方法來證明程式的正確性。多年來,他提出了許多快速且實用的演算法。

他的貢獻包括:

領域 具體貢獻
演算法 原地排序的樹狀排序演算法 (tree-sort algorithm)
尋找網路最短路徑的演算法 (algorithms for finding the shortest paths)
尋找中位數和凸包的演算法 (algorithms for finding medians and convex hulls)
理論計算 確定數位加法的極限速度 (limiting speed of digital addition)
確定電腦記憶體中排列資訊的極限速度 (limiting speeds for permuting information)
機械定理證明、拼字檢查器 許多貢獻 (numerous contributions to mechanical theorem-proving and automatic spelling checkers)

近年來,Floyd 教授一直致力於設計和實作一種主要供學生使用的程式語言。該語言將適合系統地向初學者教授結構化程式設計,並且其能力將近乎通用。

程式設計的典範

Robert W. Floyd Stanford University

Paradigm (pae.radim, -daim)... [a. F. paradigme, ad. L. paradigma, a. Gr. rctpctSetyixa pattern, example, f. rapcSEtr. pat to exhibit beside, show side by side...]

  1. A pattern, exemplar, example.

1752 J. Gill Trinity v. 91 The archetype, paradigm, exemplar, and idea, according to which all things were made. From the Oxford English Dictionary.

Permission to copy without fee all or part of this material is granted provided that the copies are not made or distributed for direct commercial advantage, the ACM copyright notice and the title of the publication and its date appear, and notice is given that copying is by permission of the Association for Computing Machinery. To copy otherwise, or to republish, requires a fee and/or specific permission. Author's address: Department of Computer Science, Stanford University, Stanford CA 94305. © 1979 ACM 0001-0782/79/0800-0455 $00.75.

今天我想談談程式設計的典範 (paradigms),它們如何影響我們作為電腦程式設計師的成功,如何應該被教授,以及如何在我們的程式語言中體現。

結構化程式設計典範

結構化程式設計 (structured programming) 是一個熟悉的程式設計典範例子,它似乎是目前大多數程式設計方法論處理方式中的主要典範。由 Dijkstra [6]、Wirth [27, 29] 和 Parnas [21] 等人提出的結構化程式設計包含兩個階段。

第一階段是自頂向下設計 (top-down design),或稱逐步精煉 (stepwise refinement),問題被分解成少量更簡單的子問題。例如,在程式設計解聯立線性方程時,第一層的分解將是將方程化為三角形形式的階段,接著是處理三角形系統的後向代入 (back-substitution) 階段。這種漸進的分解持續進行,直到產生的子問題足夠簡單可以直接處理。在聯立方程的例子中,後向代入過程會進一步分解為一個後向迭代過程,該過程從第 i 個方程找到並儲存第 i 個變數的值。更進一步的分解將產生一個完全詳細的演算法。

結構化程式設計典範的第二階段涉及從底層機器的具體物件和函式向上工作,達到在自頂向下設計所產生的模組中使用的更抽象的物件和函式。在線性方程的例子中,如果方程的係數是一個變數的數值函數,我們可能首先設計一個多精度算術表示及其程序,然後在其基礎上建立一個多項式表示及其自身的算術程序等等。這種方法被稱為抽象層級法 (method of levels of abstraction),或稱資訊隱藏 (information hiding)。

結構化程式設計典範絕非普遍接受。其最堅定的倡導者也會承認,僅靠它不足以使所有困難問題變得容易。其他更專業的高階典範,例如分支界限法 (branch-and-bound) [17, 20] 或分治法 (divide-and-conquer) [1, 11] 技術,仍然至關重要。然而,結構化程式設計典範確實有助於擴展設計能力,使得能夠建構過於複雜而無法在沒有方法學支援的情況下高效可靠地設計的程式。

軟體困境與典範的重要性

我相信當前的電腦程式設計藝術水平反映了我們在典範庫、對現有典範的知識、教授程式設計典範的方式,以及我們的程式語言如何支援或未能支援其使用者社群的典範方面的不足。

Robert Balzer [3] 最近用這些話來形容電腦程式設計的現狀:「眾所周知,軟體的狀態令人沮喪。它不可靠、延遲交付、對變更反應遲鈍、效率低下且昂貴。此外,由於目前是勞力密集型產業,隨著需求的增加和勞力成本的上升,情況將進一步惡化。」如果這聽起來像十年前左右著名的「軟體危機」,事實上我們已經處於相同的狀態十到十五年,這表明「軟體困境 (software depression)」是一個更恰當的術語。

Thomas S. Kuhn 在《科學革命的結構》(The Structure of Scientific Revolutions) [16] 中,將過去幾個世紀的科學革命描述為源於主導典範的變化。Kuhn 的一些觀察似乎適用於我們的領域。關於向學生呈現當前科學知識的科學教科書,Kuhn 寫道:

舉例來說,這些教科書似乎常暗示科學的內容完全體現在其頁面描述的觀察、定律和理論中。

同樣地,大多數關於電腦程式設計的教科書暗示程式設計的內容就是其頁面描述的演算法和語言定義的知識。

Kuhn 也寫道:

對典範的研究,包括許多比上面舉例列出的典範更為專業的典範,主要使學生準備成為將來從事實踐的特定科學社群的一員。由於他在那裡加入的人都是從相同的具體模型中學習該領域基礎的人,他隨後的實踐很少會引發根本上的公開分歧...

在電腦科學中,我們看到幾個這樣的社群,每個社群都說著自己的語言,使用自己的典範。實際上,程式設計語言通常鼓勵使用某些典範,而不鼓勵使用其他典範。有明確界定的 Lisp、APE、Algol 等程式設計學派。有些人將資料流視為程式的主要結構資訊,有些人則將控制流視為主要結構資訊。遞迴和迭代、資料結構的複製和共享、傳名呼叫 (call by name) 和傳值呼叫 (call by value),都有其擁護者。

再引 Kuhn 的話:

較舊的學派逐漸消失。其消失部分是由於其成員轉向新典範。但總會有一些人堅持一個或另一個舊觀點,他們 simply are read out of the profession,此後該領域便會忽視他們的工作。

在計算領域,沒有將這些人 read out of the profession 的機制。我懷疑他們主要成為軟體開發的經理。

Balzer 在他對軟體建構現狀的悲嘆中,接著預言自動化程式設計將拯救我們。我希望自動化程式設計師成功,但在他們 clean the stables 之前,我們最好的希望是提高我們自己的能力。我相信我們改善程式設計一般實踐的最佳機會是關注我們的典範。

典範的發明與闡述

在 1960 年代初期,上下文無關語言 (context-free languages) 的分析在編譯器開發和自然語言學中都是一個迫切重要的問題。當時發表的演算法通常既慢又不正確。據稱 John Cocke 僅用了很少的努力就找到了一個快速簡單的演算法 [2],該演算法基於一種現在標準的典範,即動態規劃 (dynamic programming) 的計算形式 [1]。動態規劃典範透過先為所有較小輸入迭代地解決問題,來解決給定輸入的問題。Cocke 的演算法成功地找到了輸入所有子字串的所有分析。在這種概念框架下,問題變得幾乎微不足道。由此產生的演算法是第一個能夠在多項式時間內統一運行的演算法。

大約在同一時期,在幾個不正確的自頂向下分析器發表後,我透過發明一種典範來解決設計一個正確的分析器的問題,該典範是找到一種處理器層次結構,類似於人類組織中雇主僱用和解僱下屬的結構,可以解決這個問題,然後模擬這個組織的行為 [8]。模擬這種多重遞迴過程使我使用了遞迴協程 (recursive coroutines) 作為控制結構。後來我發現其他處理困難組合問題的程式設計師,例如 Gelernter 的幾何定理證明機 [10],顯然也發明了相同的控制結構。

John Cocke 和我的經歷說明了程式設計的持續進步需要持續發明、闡述和交流新典範的可能性。

MYCIN [24] 程式是典範有效闡述的一個例子,該程式巧妙地診斷並推薦細菌感染的藥物。MYCIN 是一個基於規則 (rule-based) 的系統,基於一組大型獨立規則,每個規則都有一個可測試的適用條件,以及在條件滿足時產生的簡單動作。Davis 的 TEIRESIAS [5] 程式修改了 MYCIN,允許專家使用者改進 MYCIN 的效能。TEIRESIAS 程式透過從不良結果反向追蹤責任,經由允許其發生的規則和條件,直到找到一個從有效假設產生無效結果的不令人滿意的規則,來闡述該典範。透過這種方式,一位非程式設計師的醫學專家從技術上可以改進 MYCIN 的診斷能力。儘管 MYCIN 中沒有任何東西不能在一個使用條件跳轉的傳統分支決策樹中編碼,但正是規則基礎典範的使用及其隨後的自我修改闡述,使得程式的互動式改進成為可能。

擴充個人程式設計典範庫

如果程式設計一般藝術的進步需要持續發明和闡述典範,那麼個別程式設計師的藝術進步則需要他擴充其典範庫。在我自己設計困難演算法的經驗中,我發現某種技術在擴展我自己的能力方面最有幫助。在解決一個具有挑戰性的問題後,我會從頭開始重新解決它,只追溯先前解決方案的 insights。我重複這樣做,直到解決方案盡可能清晰直接為止。然後,我會尋找一個攻擊類似問題的通用規則,這會讓我在第一次就以最有效的方式處理給定的問題。通常,這樣的規則具有永久價值。透過尋找這樣的通用規則,我從先前提到的基於遞迴協程的分析演算法,發現了編寫非確定性程式 (nondeterministic programs) 的通用方法 [9],這些程式隨後透過巨集擴展轉換為常規的確定性程式。這個典範後來在人工智慧領域的電腦問題解決中發現了看似無關的用途,並體現在程式語言 PLANNER [12, 13]、MICROPLANNER [25] 和 QA4 [23] 中。

個別程式設計師獲取新典範的方式可以透過閱讀其他人的程式來鼓勵,但這受到限制,因為選擇您的同事很可能是基於他們與本地典範集的相容性。這方面的證據是我們行業經常招聘的不是程式設計師,而是 Fortran 程式設計師或 Cobol 程式設計師。Fortran 的規則可以在幾小時內學會;而相關的典範需要更長的時間,既要學會也要忘記。

接觸在不同習慣下編寫的程式可能會有所幫助。今年在 MIT 休假期間,我看到了 Lisp 程式設計師從擁有一種單一資料結構中獲得的程式設計能力的許多例子,這種結構也作為程式中所有函式和操作的統一語法結構,並具有將程式作為資料操作的能力。儘管我先前對像 Algol 家族那樣語法豐富的語言充滿熱情,但我現在清晰具體地看到了 Minsky 在 1970 年圖靈獎演講 [19] 中的觀點力量,他在演講中認為 Lisp 的結構統一性和自引用能力賦予了程式設計師能力,其內容完全值得犧牲視覺形式。我希望能將這些方法進行適當的綜合。

程式設計語言與典範支援

現在與我 1956 年進入計算領域時一樣真實的是,每個人都想設計一種新的程式語言。用寫在 Stanford University 研究生辦公室牆上的話來說:「我寧願編寫幫助我編寫程式的程式,也不願編寫程式。」在評估每年新程式語言的收成時,根據它們在多大程度上允許和鼓勵使用有效的程式設計典範來對其進行分類是很有幫助的。當我們闡明我們的典範時,我們發現它們數量龐大。Cordell Green [11] 發現,機械生成簡單的搜尋和排序演算法,例如合併排序 (merge sorting) 和快速排序 (Quicksort),需要一百多條規則,其中大部分規則可能對大多數程式設計師來說都是熟悉的典範。通常我們的程式語言對使用即使是熟悉的低級典範也毫無幫助,甚至阻礙我們。下面是一些例子。

假設我們正在模擬捕食者-獵物系統(也許是狼和兔子)的族群動態。我們有兩個方程:

W' = f(W, R)
R' = g(W, R)

這些方程給出了時間週期結束時的狼和兔子數量,作為週期開始時數量的函式。

初學者常見的錯誤是這樣寫:

FOR I : ....
DO
BEGIN
  W := f(W, R);
  R := g(W, R)
END

其中 g 錯誤地使用了 W 的修改後的值進行評估。要使程式正常工作,我們必須寫:

FOR I : ....
DO
BEGIN
  REAL TEMP;
  TEMP := f(W, R);
  R := g(W, R);
  W := TEMP
END

初學者認為我們不應該這樣做是正確的。我們最常見的典範之一,就像在捕食者-獵物模擬中一樣,是對狀態向量的組件進行同時賦值。然而,幾乎沒有任何語言有 simultaneous assignment 的運算符。我們必須 instead 經歷引入一個或多個臨時變數並透過它們來轉換新值的機械、耗時且容易出錯的操作。

再來看這個看似簡單的問題:

讀取文本行,直到找到完全空白的行。消除單字之間的冗餘空白。將文本按每行三十個字元列印,且不在行間斷字。

由於輸入和輸出都可以自然地用多級迭代表達,並且由於輸入迭代與輸出迭代不嵌套,因此在大多數程式語言中編寫這個問題非常困難 [14]。初學者花費的時間是講師預期的三到四倍,最終要么寫出一個雜亂無章的程式,要么使用明確的增量和條件執行來自製控制結構來模擬某些期望的迭代。

這個問題很自然地可以透過將其分解為三個互相通訊的協程 (coroutines) [4] 來 формулируется,分別負責字元流的輸入、轉換和輸出。然而,除了模擬語言外,我們的程式語言中很少有足夠的協程控制結構,可以自然地編寫這個問題。

當一種語言使得一種典範很方便時,我會說這種語言「支援 (supports)」這種典範。當一種語言使得一種典範可行,但不方便時,我會說這種語言「弱支援 (weakly supports)」這種典範。正如前面兩個例子所示,我們的大多數語言只弱支援 simultaneous assignment,並且根本不支援協程,儘管所需的機制比例如十七年前在 Algol 家族語言中實現的遞迴傳名呼叫 (recursive call-by-name) 程序要簡單且更有用得多。

即使是結構化程式設計典範,在我們的許多程式語言中也充其量只能得到弱支援。要將聯立方程求解器按其設計方式寫下來,人們應該能夠寫:

MAIN__PROGRAM:
BEGIN
  TRIANGULARIZE;
  BACK__SUBSTITUTE
END;

BACK__SUBSTITUTE:
  FOR I := N STEP -1 UNTIL 1 DO
    SOLVLFOR__VARIABLE(I);

SOLVE__FOR__VARIABLE(I):

TRIANGULARIZE:

Procedures for multiple-precision arithmetic
Procedures for rational-function arithmetic
Declarations of arrays

在大多數現有語言中,人們無法以這種順序呈現主程式、程序和資料宣告。通常需要一些初步的人工文本重排,這種重排很容易自動化。此外,在多個多精度程序中使用的任何變數都必須對程式中可以進行多精度算術的每個部分都是全域的,從而允許意外修改,這違反了資訊隱藏的原則。最後,將問題詳細分解為程序層次結構通常會導致效率非常低下的程式碼,儘管大多數程序由於只從一個地方呼叫,可以透過巨集擴展有效地實現。

比結構化程式設計典範更抽象的高級典範是建構語言層次結構 (hierarchy of languages),其中最高級語言的程式操作最抽象的物件,並被翻譯成下一級語言的程式。範例包括在 Lisp、Fortran 和其他語言之上建構的眾多公式操作語言 (formula-manipulation languages)。我們的大多數低級語言未能充分支援這種上層結構。例如,它們的錯誤診斷系統通常是固定的,以至於診斷訊息只有參考較低級別的翻譯後程式才能理解。

我相信,程式設計作為一門技藝的持續進步,需要開發和傳播支援其使用者社群主要典範的語言。語言的設計應該先列出這些典範,包括研究由於不支援的典範被阻止而導致的程式設計缺陷。我對我們的語言擴展(例如 Pascal [15, 28] 中的 variant records 和 powersets)並不感到滿意,只要我提到的許多其他典範仍然未被支援或弱支援。如果曾經存在程式語言設計科學,它很可能主要包括將語言與其支援的設計方法相匹配。

我不想暗示對典範的支援僅限於我們的程式語言本身。我們程式設計的整個環境,診斷系統、檔案系統、編輯器等等,都可以被分析為支援或未能支援程式設計方法的整個範圍。有希望的是這一點正被認可。例如,最近在法國 IRIA 和其他地方的工作實現了能夠感知其編輯程式結構的編輯器 [7, 18, 26]。任何嘗試執行即使是簡單任務(例如更改程式中作為識別符號出現的每個 X,而不會無意中更改所有其他 X)的人都會欣賞這一點。

程式設計的教學

現在我想談談我們教授的電腦程式設計。我們對形式而非內容的不幸執著,Minsky 在他的圖靈獎演講 [19] 中對此表示哀嘆,這體現在我們典型的教學選擇中。如果我問另一位教授他在入門程式設計課程中教什麼,無論他是自豪地回答「Pascal」還是謹慎地回答「FORTRAN」,我知道他教的是一種語法、一組語義規則,以及一些已完成的演算法,而讓學生自己去發現某種設計過程。即使是基於結構化程式設計典範的教科書,雖然在最高層次(我們稱之為程式設計的「故事」層次)提供了指導,但往往在中層次(我們稱之為「段落」層次)沒有提供幫助。

我相信可以明確教授一套針對所有層次程式設計設計的系統方法,並且經過這樣訓練的學生比傳統上完全透過學習已完成程式來教學的學生有很大的優勢。

以下是一些我們可以教授的範例。

當我向學生介紹程式語言的輸入功能時,我會介紹一種標準的互動式輸入典範,形式是一個我稱為 PROMPT_READ_CHECK_ECHO 的巨集指令,它會一直讀取直到輸入資料滿足有效性測試,然後將其回顯到輸出檔案。這個巨集在一個層面上本身就是迭代和輸入的典範。同時,由於它讀取的次數比說「Invalid data」多一次,它實現了一個更通用、先前教授的「n 又二分之一次」循環典範。

PROMPT_READ_CHECK_ECHO: arguments are a string PROMPT, a variable V to be read, and a condition BAD which characterizes bad data;

PRINT_ON_TERMINAL(PROMPT);
READ_FROM_TERMINAL(V);
WHILE BAD(V) DO
BEGIN
  PRINT_ON_TERMINAL('Invalid data');
  READ_FROM_TERMINAL(V)
END;
PRINT_ON_FILE(V)

它在更高層面上也實現了程式設計師對程式使用者的責任,包括程式的每個組件都應該受到保護,免受該組件未設計的輸入的影響。

Howard Shrobe 和 MIT 的 Programmer's Apprentice group [22] 的其他成員成功地教導他們的初學者學生一種廣泛應用的典範,他們稱之為 generate/filter/accumulate。學生們學會識別許多表面上不同的問題,這些問題由列舉集合的元素、篩選出一個子集,以及累積子集中元素的某些函式組成。學生們使用的 MACLISP 語言 [18] 支援這種典範;學生們只需要提供產生器 (generator)、過濾器 (filter) 和累積器 (accumulator)。

我之前提到的捕食者-獵物模擬也是一種通用典範的實例,即狀態機典範 (state-machine paradigm)。狀態機典範通常涉及透過一組儲存變數的值來表示計算的狀態。如果狀態很複雜,轉換函式需要一種設計典範來處理同時賦值,特別是考慮到大多數語言只弱支援同時賦值。為了說明這一點,假設我們要計算:

       1   1    1·3    1·3·5
S = arcsin - = - + ----- + ------- + --------- + '''
       2   2   2·3·2   2·4·6·5   2·4·6·8·7

我在每個加數的有用部分上畫了圈,這些部分有助於計算右邊的下一個加數。如果不描述此類過程的整個設計典範,狀態轉換設計的一部分是系統地找到從

Q = 1.3 / (2.4), C = 5
S = 1/2 + 1.3 / (2.4.3)

Q' = 1.3.5 / (2.4.6), C' = 7
S' = 1/2 + 1.3 / (2.4.3) + 1.3.5 / (2.4.6.7)

的方法。有經驗的程式設計師已經將這一步驟內化,並且在除了最複雜的情況下,都會無意識地執行它。對於初學者來說,明確地看到典範使他們能夠解決比沒有幫助時更複雜的狀態機問題,更重要的是,鼓勵他們自己識別其他有用的典範。

大多數在電腦程式設計教科書中找到的經典演算法可以被視為更廣泛典範的實例。Simpson 規則是極限外推 (extrapolation to the limit) 的一個實例。Gaussian elimination 是透過遞迴下降 (recursive descent) 解決問題,然後轉換為迭代形式。合併排序 (Merge sorting) 是分治典範的一個實例。對於每一個這樣的經典演算法,人們都可以問:「我是如何發明這個的?」並找回一個應該同樣經典的典範。

結論

總而言之,我對嚴肅的程式設計師說:花一部分工作時間檢視和精煉自己的方法。儘管程式設計師總是在努力達到某個未來或過去的截止日期,但方法論抽象是一個明智的長期投資。

對於程式設計教師,我更要說:盡可能完整地確定你使用的典範,然後明確地教授它們。當 Fortran 取代拉丁文和梵文成為典型死語言時,它們將對你的學生有所幫助。

對於程式語言設計師,我說:除非你能支援我程式設計時使用的典範,或者至少支援我擴展你的語言使其支援我的程式設計方法,否則我不需要你的閃亮新語言;就像一輛舊車或舊房子一樣,舊語言有我已經學會適應的限制。要說服我相信你的語言的優點,你必須向我展示如何在其中建構程式。我不想阻止新語言的設計;我想鼓勵語言設計師成為設計過程細節的認真學習者。

致謝

謝謝 ACM 的成員們,感謝你們提名我進入圖靈獎得主這一傑出人士的行列。沒有人能在沒有幫助的情況下達到這個位置。我欠許多人的情,尤其要感謝四位:Ben Mittman,在我早期職業生涯中幫助並鼓勵我追求計算領域的科學和學術方面;Herb Simon,我們行業的文藝復興人,與他交談本身就是一種教育;已故的 George Forsythe,他為我提供了程式設計教學的典範;以及我的同事 Donald Knuth,他樹立了傑出的智慧誠信榜樣。我也很幸運擁有許多優秀的研究生,我認為從他們那裡學到的東西與我教導他們的差不多。

對於你們所有人,我深感感激和榮幸。

Received April 1979

參考文獻

  1. Aho, A.V., Hopcroft, J.E., and Ullman, J.D. The Design and Analysis of Computer Algorithms. Addison-Wesley, Reading, Mass. 1974.
  2. Aho, A.V., and Ullman, J.D. The Theory of Parsing, Translation, and Compiling, VoL 1: Parsing. Prentice-Hall, Englewood Cliffs, New Jersey, 1972.
  3. Baker, R. Imprecise program specification. Report ISI/RR-75-36, Inform. Sciences Inst., Dec. 1975.
  4. Conway, M.E. Design of a separable transition-diagram compiler. Comm. ACM 6, 7 (July 1963), 396---408.
  5. Davis, R. Interactive transfer of expertise: acquisition of new inference rules. Proc. Int. Joint Conf. on Artif. Intell., MIT, Cambridge, Mass., August 1977, pp. 321-328.
  6. Dijkstra, E.W. Notes on structured programming. In Structured Programming, O.J. Dahl, E.W. Dijkstra, and C.A.R. Hoare, Academic Press, New York, 1972, pp. 1-82.
  7. Donzeau-Gouge, V., Huet, G., Kahn, G., Lang, B., and Levy, J.J. A structure oriented program editor: A first step towards computer assisted programming. Res. Rep. 114, IRIA, Paris, April 1975.
  8. Floyd, R.W. The syntax of programming languages--a survey. IEEE EC-13, 4 (Aug. 1964), 346-353.
  9. Floyd, R.W. Nondeterministic algorithms. J.A CM 14, 4 (Oct. 1967), 636-644.
  10. Gelernter. Realization of a geometry-theorem proving machine. In Computers and Thought, E. Feigenbaum and J. Feldman, Eds., McGraw-Hill, New York, 1963, pp. 134-152.
  11. Green, C.C., and Barstow, D. On program synthesis knowledge. Artif. Intell. 10, 3 (June 1978), 241-279.
  12. Hewitt, C. PLANNER: A language for proving theorems in robots. Proc. Int. Joint Conf. on Artif. Intell., Washington, D.C., 1969.
  13. Hewitt, C. Description and theoretical analysis (using schemata) of PLANNER... AI TR-258, MIT, Cambridge, Mass., April 1972.
  14. Hoare, C.A.R. Communicating sequential processes. Comm. ACM 21, 8 (Aug. 1978), 666-677.
  15. Jensen, K., and Wirth, N. Pascal User Manual and Report. Spfinger-Verlag, New York, 1978.
  16. Kuhn, T.S. The Structure of Scientific Revolutions. Univ. of Chicago Press, Chicago, II1., 1970.
  17. Lawler, E., and Wood, D. Branch and bound methods: A survey. Operations Res. 14, 4 (July-Aug. 1966), 699-719.
  18. MACLISP Manual. MIT, Cambridge, Mass., July 1978.
  19. Minsky, M, Form and content in computer science. Comm. A CM 17, 2 (April 1970), 197-215.
  20. Nilsson, N.J. Problem Solving Methods in Artificial Intelligence. McGraw-Hill, New York, 1971.
  21. Parnas, D. On the criteria for decomposing systems into modules. Comm. ACM 15, 12 (Dec. 1972), 1053-1058,
  22. Rich, C., and Shrobe, H. Initial report on a LISP programmer's apprentice. IEEE J. Software Eng. SE-4, 6 (Nov. 1978), 456---467.
  23. Rulifson, J.F., Derkson, J.A., and Waldinger, R.J. QA4: A procedural calculus for intuitive reasoning. Tech. Note 73, Stanford Res. Inst., Menlo Park, Calif., Nov. 1972.
  24. Shortliffe, E.H. Computer-based Medical Consultations: MYCIN. American Elsevier, New York, 1976.
  25. Sussman, G.J., Winograd, T., and Charniak, C. MICRO-PLANNER reference manual. AI Memo 203A, MIT, Cambridge, Mass., 1972.
  26. Teitelman, W., et al. INTERLISP manual. Xerox Palo Alto Res. Ctr., 1974.
  27. Wirth, N. Program development by stepwise refinement. Comm. ACM 14, (April 1971), 221-227.
  28. Wirth, N. The programming language Pascal. Acta Informatica 1, 1 (1971), 35-63.
  29. Wirth, N. Systematic Programming, an Introduction. Prentice-Hall, Englewood Cliffs, New Jersey, 1973.