本節書摘來自華章計算機《從問題到程式:用python學程式設計和計算》一書中的第1章,第1.1節,作者:裘宗燕 更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。
我們已經生活在資訊時代,環顧四周,資訊技術的影響無處不在。由于資訊科學技術的發展和應用,我們的世界的方方面面都與20年前大不相同了,例如:
個人生活:看看人們在每天生活中做的各種事情,有多少是在與螢幕鍵盤(可能是觸摸屏)互動,這些都是20年前沒有的事情。
人際交流:20年前的人際交流方式很簡單。除面對面交流外,隻能通過紙筆寫信或長途電話(要找專門的電話或者到電話局)。今天人手一部手機,可以通過電話、短信、各種網絡即時消息互相交流。電子郵件也是私人之間的交流媒介,而在網上的各種地方發帖和回複,則帶有公開性質,是人際交流的新方式。
學習和教育:課堂教育的方式和手段都改變了。網際網路越來越多被用于學習和知識的發掘整理,通過電子手段擷取資訊和知識的比重越來越大。
産業和職業:出現了大量與資訊處理有關的職業,資訊技術在越來越多的業務和工作領域發揮着越來越大的作用,各種職業的工作方式都改變了。
資訊技術已經滲入經濟、政治、社會生活的所有方面,具體的事例不勝枚舉。
為什麼在這不長的幾十年時間裡,人類社會的方方面面會發生這麼大變化?回答很簡單:因為有了計算機,這種強大、靈活、威力無窮的通用資訊處理工具(它從根本上有别于人類發明的其他工具),改變了人類社會的每個方面。
那麼,計算機的威力從哪裡來?為什麼一台計算機(基于電子元器件組合起來的一套裝置)能完成如此豐富多彩的不同工作?本章首先希望回答這個問題。
本章将幫助讀者在比較直覺的層面建立起對計算機、計算、程式、程式設計和程式設計語言的基本認識,然後簡單介紹本書使用的程式設計語言——python語言,最後介紹在學習實際程式設計中必然遇到的一些情況和問題。
人類發展的曆史,也是積累知識的曆史。今天的人們未必比古人更聰明,至少相差不會太多。但是,今天人們掌握的知識比古人多得多,而且一年多于一年,一代多于一代。正是由于這種知識積累,使今天人類的生活與古人大不相同了。
1.1.1 “是什麼”和“怎樣做”的知識
人類積累的知識,從某種角度看可分為兩大類:
一類是有關“是什麼”的知識,人們通過觀察、分析、研究、試驗等活動,設法認識所見所聞的事物,了解這些事物,設法解釋事物的方方面面。
另一類是有關“怎樣做”的知識,這些知識告訴人們如何去改變各種現存的事物,或者去創造從未有過的新鮮事物。
顯然,這兩類知識互相有聯系,但又有各自不同的特點。它們不僅内容不同,表述的方式和手段通常也大不相同。下面看兩個例子。
兩個執行個體
在日常生活和學習中,到處都可以看到這兩類不同知識,現舉兩例:
【例1.1 菜單和菜單】以常見的菜肴——蕃茄炒雞蛋為例,在飯店菜單上可以看到對它的描述:通過自然語言寫出,介紹其色香味方面的特點,可能再附以照片給人感官印象。這是有關該菜肴的一套說明性描述,說明了蕃茄炒雞蛋是什麼。而翻開一本菜單,其中有關同一菜肴的描述則完全不同。首先是一個配料表,說明制作這一菜肴需要準備哪些基本食材和配料,烹制前如何處理(準備工作)。而後是有關用火和烹制過程的詳細說明,告訴人們應該怎樣做,才能得到一盤合格的蕃茄炒雞蛋。
顯然,上述兩種說明都針對同一客體,即同一盤菜肴,但它們顯然很不一樣。前者傳遞的是有關“是什麼”的知識,或稱說明性的知識,而後者傳遞的是有關“怎樣做”的知識(操作性的,或稱為過程性的知識)。作為飯店顧客,查閱菜單弄清菜肴的特點,符合自己的需要,就可以選擇它。而作為學做菜的人們則需要參考菜單實際操作,才能做出合乎預期的菜肴。
【例1.2 最大公約數】最大公約數是基礎數學中的一個基本概念,出現在國小數學課本裡。作為數學概念,最大公約數有嚴格的數學定義:
定義:兩個正整數x和y的最大公約數(常簡寫為gcd),就是能整除x并能整除y的正整數中最大的那個數(允許至多一個數為0是本定義的擴充)。
這個定義基于幾個更基本的數學概念(正整數、整除、最大),嚴格定義了一個新概念:最大公約數。隻要了解了這幾個基本概念,就能了解這個新概念。顯然這一定義傳播的一些知識屬于是什麼的說明性知識。但是這個定義沒有說明在遇到一對正整數時,如何把它們的最大公約數求出來。後一工作就要靠過程性的知識了。
求最大公約數的一種著名方法稱為輾轉相除法,又稱為歐幾裡得方法。該方法說明了求兩個正整數的最大公約數的一種計算過程,可嚴格描述如下:
計算的基礎(輸入):正整數x和y
求出x除以y的餘數r
如果r等于0,y就是兩個數的最大公約數,計算成功結束
将y作為新的x,r作為新的y,回到步驟1繼續
這裡的每一行描述一兩個簡單操作,做計算時隻需一行行地往下做。最後兩行有點特殊:第3行說明滿足一定條件就得到了結果;第4行說明要轉回前面繼續。
如果給定一對正整數x和y,實施上面描述的計算過程,最後就能得到它們的最大公約數。進一步說,要執行這個計算過程,需要知道如何完成兩個基本操作:求一個整數除以另一個整數的餘數,判斷一個整數是否為0。
過程性知識
說明性和過程性的知識都非常重要,前者是人們有關客觀事物的樸素認識的深入、積累和總結,而後者則是人們對自己的各方面實踐活動的總結。
本書主要關注後一類知識(過程性知識)。其表現形式可能是一段自然語言說明,也可能采用某些特殊的格式(例如上面有關求最大公約數的描述,或者菜單裡有關一個菜肴的描述)。但是,這類知識重要性,主要不在于其描述的形式,而在于它所描述的(操作、計算)過程可以實施,最終産生出所期望的結果或者效果。
曆史上人們早已發明了許多有價值的計算過程,但實施卻很困難,因為隻能由人按照特定的方法一步步計算,需要大量人力,也極端費時。有很多著名的例子,例如,開普勒花了近10年時間計算太陽系的行星軌道;二戰中美國陸軍部為計算大炮的裝藥和彈道,雇傭了成百的美國婦女參與計算彈道手冊等。
近幾十年來,由于人類發明了計算機這種自動化的計算機器,過程性知識的重要性大大提升了。以計算機作為過程自動化的基礎,社會生産生活的方方面面都已經發生了巨大變化,而且,這一變化趨勢還在繼續,沒有看到絲毫減退的迹象。今天在幾乎任何領域中,一旦人們弄清了一件事可以怎麼做,就會考慮如何借助于計算機去完成它。
1.1.2 計算和程式
環顧四周,計算機已經是今天人類使用最廣泛的一種機器了。它不但以獨立可見的形式出現在家庭、辦公室和許多其他地方,還被嵌入在幾乎所有現代化的裝置、儀器、家用器具中。為什麼計算機這麼有用?為什麼計算機到處都能用?實際上,計算機就是一種能自動完成計算的機器,要了解計算機,就需要了解計算。人們從國小(或者學齡前)就開始接觸計算,學習基本計算規則。那麼計算是什麼?
計算是一類按規則操作抽象符号(序列)的過程。例如,最基本的整數算術就是操作算術表達式(由10個數字元号和幾個表示運算的符号構成的序列)。人們使用一組基本算術規則,從需要計算的符号序列出發,逐漸變換,最後得到計算結果。人類社會發展(如計量、配置設定、度量等)産生了計算的需求,逐漸發明了與計算有關的各種記法和過程。在計算機出現前,計算由人(通過頭腦和手等)實施,可能借助一些簡單工具(手指、紙筆、算盤、計算尺)。越來越煩瑣的計算,需要花費非常多的人力和物力,也限制了很多工程技術的發展。今天,計算機已經把人從包含大量細節的煩瑣計算中解放出來了。
要了解計算機和計算,也必須了解程式的概念,了解計算、程式和計算機之間的關系。讨論程式和程式設計(程式設計)就是本書的主題。
程式與計算
“程式”一詞來自生活,通常指為完成某項事務而确定的一套既定活動方式或者活動安排。在表述上,程式應看作是對一系列動作的進行過程的描述。日常生活中也可以找到許多“程式”執行個體。例如,下面序列描述了一個學生早晨起床後的活動:
起床
刷牙
洗臉
吃早飯
去教室上課
這是一個直線型序列,包含一系列簡單活動(步驟),是最簡單的程式形式。如果按順序實施序列中描述的動作,最後的效果就是完成了一項事務或者工作。
另一個複雜一些的過程是完成一門數學課程的作業,可以描述為:
完成準備工作(如準備筆、打開作業本、打開書籍等)
找到要做的一道習題
如果習題簡單,完成後轉到第5步
如果習題複雜
4.1 仔細審題、思考、查閱教科書和參考書等
4.2 完成習題
如果還有未完成的習題,轉到第2步繼續
顯然,這個程式比前一個複雜些。最主要複雜性在于它不是一個平鋪直叙的序列,其中有些步驟有條件,需要根據情況處理,還可能出現重複的動作或動作序列。
仔細探究這個執行個體,可以看到它還可能進一步細化,以便處理實際中可能遇到的各種複雜情況。例如步驟4.1,其中的審題、思考和查閱書籍又可能交替進行,可能出現多次反複。還可能遇到各種異常情況,例如作業本用完了、筆出了故障、電話鈴突然響了,或者到了上課或吃飯時間等。由此可見,要把一個“程式”描述完全并不容易。
現實生活中有許多這樣的程式性活動,典型的如一個會議的議程、一場演出的節目單、運動會的程式冊。總而言之,對一項事務、活動等的進展過程的細節描述就是一個“程式”。一個程式的描述通常有開始與結束,動作者(人或機器)根據程式執行一系列動作,到達程式結束位置時,整個工作完成。在一個程式描述中,總有一批預先假定的“基本動作”。例如,上面有關作業的描述中把“查閱參考書”看作基本動作。但如果參考書在圖書館,那麼這個動作就需要進一步分解。程式的精細化(精化,或稱功能分解)也是在本書後面有關計算機程式設計的讨論中特别強調的最本質的東西。
在計算中做的都是程式性的工作,通過一系列較為簡單的操作完成。以多位數加法為例,需要數字對位等準備,然後使用基本數字加法規則,從低位到高位逐位求和并處理進位,直至做完所有數位,最後收集結果。有關計算過程可以描述如下:
準備工作:将需要求和的兩個數按位對齊
把個位作為目前位,進位值記為0
如果兩個數的目前位都有值
3.1 算出兩個數的目前位再加進位值之和以及新的進位值(0或1)
3.2 把得到的和記入和數的目前位,轉到第5步繼續
如果隻有一個數的目前位有值,用a表示這個數
4.1 算出a的目前位加進位值之和及新進位值
4.2 把得到的和記入和數的目前位
4.3 把更高一位作為目前位
4.4 如果a的目前位仍有值,轉到第4.1步繼續
4.5 如果進位值是0,結束
4.6 把1記入和數的目前位,結束
将更高一位作為目前位
如果兩數的目前位都已經無值
6.1 如果當時進位值是0,結束
6.2 把1記入和數的目前位,結束
轉回第3步繼續
這裡的基本執行方式是執行完一步後執行下一步,除非目前步驟中明确要求下一步做什麼。有些步驟有條件,如果目前步驟的條件不成立,就直接轉去執行下一步的操作。雖然多位數加法是人們最熟悉的計算,将其詳細地嚴格寫出還是有點煩瑣。顯然這裡也有開始和結束,有特定的基本操作(一位十進制數的加法,判斷一個數字是否0)。乘法的計算過程更複雜,其中需要做逐位的乘法、結果的對位和加法計算等。
日常生活中的程式可以看作計算機程式的直覺對應物,在一些情況下也會明确寫出實際文本,例如一次會議程式或演出節目單。但兩者之間還是有巨大差異,主要在于後者的極端嚴格性。日常生活中程式性活動的描述可以含糊籠統,實際執行也可以有變化調整,不一定完全按程式走。而計算機程式的描述則要求絕對嚴格,計算機作為執行主體,對程式的執行一絲不苟,一步步按程式中的條目行事,絲毫沒有商量的餘地。
計算機和程式
為了研究計算的理論,數學家阿蘭•圖靈在1936年提出了一種計算模型,後來被人們稱作圖靈機。這是一種非常簡單的抽象計算機器(可以看作一種數學模型),其中有一個控制部件,指揮一個讀寫頭在一條記錄資料的帶子上讀寫資料。著名的圖靈-丘奇論題說,對于任何可以通過計算解決的問題,都可以設計一台圖靈機解決。人們用這個論題定義什麼是計算。圖靈還證明了計算的局限性,通過執行個體證明了不可計算問題的存在性。
圖靈還有另一個特别重要的貢獻:他在圖靈機模型的基礎上設計了一台稱為通用圖靈機的特殊圖靈機,并證明了通用圖靈機能模拟任何一台圖靈機的工作過程,也就是說,能完成任何可能的計算工作。圖靈的做法是把具體圖靈機表達為通用圖靈機可以處理的編碼表示形式,實際上就是程式。是以,通用圖靈機是一種可程式設計的通用機器,可以看作今天的通用電子計算機的理論模型,是以圖靈被人們稱為“計算機之父”。
有關圖靈機(和圖靈-丘奇論題)和通用圖靈機的工作非常重要。前者告訴我們,如果需要考慮設計和制造完成計算的機器,隻需要考慮計算能力“等價于”圖靈機模型的機器就足夠了。後者告訴我們,不需要考慮如何去設計能完成千奇百怪的具體計算的裝置(例如加法機、乘法機、文字編輯機、超級瑪麗遊戲機等),隻需要設計和制造出一種裝置,其功能等價于通用圖靈機,就能解決所有的計算問題了。
現實中的計算機是20世紀40年代人們發明的一種自動機器,基于電子技術,能完成各種計算工作。從20世紀30年代末開始,各國的研究者們開始基于電子技術開發出一些計算裝置。早期的這類裝置隻能做一件專門計算工作,是功能固定的計算裝置。例如1942年完成的abc機器(atanasoff-berry computer)專門求線性方程組的數值解,圖靈上司開發的bombe(意為密碼破解)機器專門破解德國enigma密碼機生成的密碼。
1946年在美國賓州大學開始運作的eniac是第一台得到較多實際使用的可程式設計計算機,隻需要給它換一個“程式”,它就能做另一種計算工作。但是,這台機器的程式由一些外部連線和開關設定組成,要想換一個程式,需要重新連接配接許多線路,改動很多開關。這件事通常需要許多人工作幾天時間,非常麻煩。
著名數學家馮•諾依曼考察了eniac機器之後寫出了一份報告,提出了采用程式存儲方式的計算機的邏輯設計,為現代計算機的發展指明了正确方向。程式存儲計算機的特點就是把需要執行的程式編碼,像資料一樣存入計算機的存儲器,然後讓計算機的執行部件自動提取程式的内容,執行相應操作。這樣,一方面計算機能擺脫外部拖累,用自己的速度快速執行程式。另一方面,給計算機換一個程式,就像是給它輸入一組資料一樣,非常友善。具有這種結構的計算機被稱為馮•諾依曼計算機。1948年英國曼切斯特大學研究者開發出mark i計算機,通常被認為是第一台實際投入使用的程式存儲計算機。
其實,所謂的馮•諾依曼計算機,也就是圖靈理論中的通用圖靈機的一種具體展現形式,是一台通用的計算裝置。而完成具體計算的計算機程式,對應于圖靈的通用圖靈機理論中的具體圖靈機的編碼表示形式。也就是說,人們在設計和實作計算裝置方面的多年實際探索,最終再次證明了圖靈理論的重要意義。
計算機的基本原理
計算機能執行一組基本操作,每個操作完成一個簡單動作,例如做一次整數運算、把一個數從這裡搬到那裡、比較兩個數的大小等。計算機提供了一套指令,每種指令對應計算機的一個基本動作。最基本的計算機程式,就是一個這種指令的序列。
計算機的基本原理很簡單,就是能自動地按照程式要求一步步工作。其工作方式如圖1.1所示,這是一個循環,循環中不斷地交替執行兩個動作:第一個動作是取得程式裡的一條指令,第二個動作是執行該指令要求的操作。完成一次基本循環後進入下一個循環,再次取得下一條應該執行的指令并執行它。周而複始,直至遇到一條明确要求它停止工作的指令。這個圖表現了計算機運作的微觀情況。
要指揮計算機工作,最基本的方式就是寫出一個程式,把這個程式提供給計算機,指令計算機去執行它。此後計算機就會按照程式的描述,一絲不苟地執行其中的指令,直至整個程式執行結束。是以,從宏觀上看到的計算機工作的情況如圖1.2所示:獲得一個程式,執行它,可能給出得到的結果;然後取得人們提供的下一個程式,執行并給出結果。同樣是循環往複。人們常把計算機執行程式的過程簡單說成是程式的執行過程。
https://yqfile.alicdn.com/569ccaf278dd34ad460696d98cf5637a95ebb33e.png" >
計算機是一種通用計算機器,給了它一個或一組程式後,它就變成了一個處理某種專門問題,完成特殊工作的專用機器。例如,給它(在其上執行)一個文字處理程式,它就變成了一台文字處理機器;給它一個遊戲程式,它就變成了一台遊戲機器。通過技術,還可以同時在一台計算機上運作多個程式,使人可以把它當作多部不同的機器,同時使用。
這種通用性與專用性的統一非常重要:從一方面看,一種或不多幾種計算機可以通過現代化工業的方式大量生産,使工程師們可以專心研究這幾種裝置的各方面改進,提高性能、降低成本、縮小體積等;另一方面,通過運作不同的程式,一台計算機可以在不同時候處理不同問題,甚至同時處理許多不同問題。這些就是計算機之威力的根源。這種通用性和專用性的統一,為資訊科學技術領域的大發展奠定了堅實的基礎。
今天,計算機的發展及其在各領域的廣泛應用,對人類社會各方面的深刻影響已經是人人皆知的事實了。計算機之是以能産生這樣大的影響,其原因不僅在于人們發明并大量制造了這種令人敬畏的奇妙機器,更重要的是人們為計算機開發出了數量宏大、五彩缤紛、能指揮計算機完成各種簡單或複雜工作的程式。目前正在使用的計算機并沒有多少種,正是數量繁多、功能豐富多彩的程式給了計算機無窮無盡的“生命力”。
作為通用的機器,計算機有應用于各種領域、解決各種問題的潛力。但是,要真正将其應用于任何具體問題,都需要有完成這種具體工作的程式,需要有人把這種程式開發出來。人們把描述(編制、構造、開發)程式的工作稱為程式設計或者程式設計,這種工作的産品就是程式。由于計算機的本質特征,從計算機誕生之初就有了程式設計工作。今天,程式設計已經變成了一個需要很多人去做的實際工作,而且還有更多的人多多少少需要做一些程式設計工作。學習計算和程式設計不僅可以成為一些人的職業基礎,也是了解今天社會生産和生活方方面面的新特征,了解所有科學技術和社會發展的一條重要線索。
1.1.3 程式設計語言
要指揮計算機做某件工作,就要給它一個程式,其中說明計算機在工作過程中應該怎樣做,給出完成所需工作的程式性活動的一步步細節,描述計算機執行中需要做的動作及其執行順序。為了描述這種過程,需要有一種适當的描述方式。一套系統的描述方式就形成了一種語言。在這裡需要的是一種人能使用、計算機也能處理的符号描述形式,這樣一套描述形式就是一種程式設計語言。這是一類人造的語言。程式設計語言也常被稱為程式設計語言,或簡稱為程式語言,本書中也經常簡單将其說成語言。
有人可能說:國小生就學了數學,數學的一個基本部分是計算,國小生已經會用數學方式(或說用數學語言)描述計算過程,程式設計語言還有什麼特殊之處嗎?确實有!程式設計語言的突出特點就在于不僅人能懂得和使用它,計算機也能“懂得”它,能按用程式設計語言描述的程式去行動,完成所需要的計算工作。是以,程式語言既是人描述計算的工具,也是人與計算機交流資訊的基本媒介。人通過用程式設計語言寫程式的方式指揮計算機完成各種具體工作。當然,程式設計語言也是人與人交流有關計算的想法和過程的工具,一個人寫的程式可能被其本人後來閱讀,或者被其他人閱讀。這方面的作用也影響着程式設計語言的發展。
機器語言和彙編語言
在計算機内部,一切資訊都以二進制編碼的形式存在。需要存入計算機,要求計算機執行的程式也不例外。計算機都規定了一套描述其指令的二進制編碼形式,這種描述形式稱為機器語言,用機器語言寫的程式稱為機器語言程式。計算機能直接“了解”并執行這種程式。下面是一台假想計算機上的一個機器語言程式,也就是一個指令的系列:
這裡描述的程式包含6條指令,要求計算機做的事情就是計算算術表達式a × b + c的值。為便于了解,這裡用a、b、c代表計算機裡的三個存儲單元,它們的位址分别為1000、1010和1100。這個程式描述了完成這一計算,最後将結果存入單元1110的計算過程。上面提到的寄存器是一類存儲資料的部件,計算機硬體可以直接操作其中資料,儲存在其他地方(例如記憶體單元)的資料需要先裝入寄存器,然後才能在計算中使用。
計算機誕生之初,人們隻能用機器語言寫程式。由上面的簡單例子可見,對于人的使用而言,二進制編碼形式的機器語言非常不友善:用它寫程式非常困難,工作效率極低,寫出的程式難以了解,正确性很難保證,發現程式有錯也很難辨認和改正。
複雜的程式可能包含成百萬、成千萬條,甚至更多條指令,其中的執行流程錯綜複雜,了解一個二進制機器語言描述的複雜程式到底做了什麼,很容易變成人力所不能及的事情。為了緩解這個問題,人們很快開發出符号形式的、相對更容易使用的彙編語言。用彙編語言寫的程式需要通過專門軟體(稱為彙編系統)加工,翻譯成機器語言後送給計算機執行。下面是用某種假想的彙編語言寫的程式,它完成與上面程式同樣的工作:
彙編語言的每條指令對應一條機器語言指令,其中用助記的符号名表示操作和存儲單元。這樣,每條指令的意義都更容易了解和把握,了解整個程式也容易了許多。但是,彙編語言沒有結構,一個程式是基本指令的一個長序列,是一盤散沙。用彙編語言編寫複雜程式仍然很困難,難以了解,其中的錯誤也很難被定位和改正。
進階程式設計語言
1954年誕生了第一個進階程式語言fortran,程式設計進入了一個新時代。fortran采用完全符号化的描述形式,用類似數學表達式的形式描述資料和計算。語言中提供了有類型的變量,作為計算機存儲單元的抽象。它還提供了一些進階流程控制機制,如循環和子程式等。這些進階機制使程式設計者擺脫了許多具體的計算機硬體細節,可以把複雜的程式分解為一些較小的較容易把握的部分,友善了複雜程式的書寫。寫出的程式更容易閱讀,發現錯誤後也更容易辨認和改正。fortran語言誕生後受到廣泛歡迎。
從fortran語言誕生至今,人們提出的語言已經有數千種,其中大部分是試驗性語言,隻有少數語言得到廣泛使用。随着時代的發展,今天絕大部分程式都是用進階語言寫的,人們也已習慣于用程式設計語言這一術語特指各種進階程式語言了。用進階語言描述前面的程式隻需要一行。例如,下面是用本書中将要使用的python語言寫出的完成同樣計算的程式:
d = a * b + c
這一行程式要求計算機算出 = 符号右邊表達式的值,最後用d記錄計算的結果。這種表示方式接近人們熟悉的數學形式,明顯更容易閱讀和了解。
與機器語言和彙編語言相比,進階語言的形式人更習慣,更容易使用,這也使更多的人願意參與到程式設計活動中。用進階語言寫程式,工作效率更高,使人能開發出更多應用系統,這些又反過來推動了計算機應用的發展,進而推動了計算機工業的大發展。可以說,進階程式設計語言的誕生和發展,對計算機領域的發展起到決定性作用。
當然,計算機也不能直接執行進階語言描述的程式。人們在設計好一個進階語言後,還需要開發一套實作該語言的軟體,這種軟體被稱作進階語言系統,也常說成是這一進階語言的實作。在研究開發各種進階語言的過程中,人們深入研究了實作語言的技術。進階語言的基本實作方式有兩種,分别稱為編譯和解釋:
1)編譯方式:首先針對要實作的語言開發出一個翻譯軟體,它能把用這個語言寫的程式翻譯成計算機機器語言的等價程式。我們在用這種進階語言寫出一個程式p之後,先用上述翻譯程式處理,得到與p對應的機器語言程式p'。在此之後,隻要指令計算機執行程式p',計算機就能完成程式p要求的計算工作了。
2)解釋方式:首先針對要實作的語言開發一個解釋系統,該系統能讀入用這種語言寫的程式,直接按程式的要求指揮計算機完成相應的計算工作。要運作一個寫好的程式,隻要把它送給運作着上述解釋系統的計算機,就可以完成程式要求的工作了。
有許多進階語言适合采用第一種方式實作,如fortran、c語言等,也有許多語言适合采用第二種方式或某種混合方式。從表面看,本書中使用的python是采用解釋方式實作的語言,但其中還有些細節。後面會介紹python語言實作的一些情況。
随着計算機科學技術的發展,人們不斷開發出新的程式語言,老的語言也被逐漸淘汰,仍在用的老語言也在不斷變化。以fortran為例,它在過去60年中經曆了多次大改版,其較新版本(如fortran 90、95、2003和2008)與早期fortran相比已經有很大不同。其他曆史較長的語言也都如此。推動語言發展的因素很多。随着程式設計工作的長期實踐,人們對程式設計應該怎樣做、需要什麼東西去描述程式等,不斷産生新的認識,其中許多重要認識被凝結到新語言裡。推動語言發展的另一原因是應用。新的應用領域常對描述工具提出新要求,這些認識和要求促使人們改造已有的語言,或者提出新語言。
目前世界上使用較廣的語言有c、java、c++、python等,這些語言通常被看作正常語言,因為它們有許多常見的共同特征。還有一些語言比較特殊,在形式和程式設計方式等方面與正常語言差異很大,它們互相之間也常常大相徑庭。這些非正常的語言各具特點,有些語言有自己的應用領域,甚至有特殊的使用人群。這一類語言包括lisp、smalltalk、prolog、ml等。雖然不如正常語言使用廣泛,但這些語言也非常重要,它們都曾在程式語言或計算機的發展曆史上起過(有些仍然起着)極其重要的作用。
上面說的都是通用程式設計語言,其設計目标具有一般性,希望能用于解決範圍廣泛的計算問題。除此之外,現在還發展出許多專用的程式設計語言,或者比較偏向于應用于某些問題的程式設計語言。常見的如maple和mathematica用于做符号計算和數學問題的計算,sas和r等用于做與統計有關的計算,matlab等用于做矩陣計算和工程計算。還有許多專用于很窄的特殊問題的語言,例如專用于控制某種數控機床,專用于某類機器人的動作設計,專用于特殊的編織機器的花紋設計等。這些語言各有特點,但從程式性的角度看,它們也繼承了通用語言的一些基本概念和特征。
如前所說,進階語言的發展推動了計算機應用和整個計算機領域的發展,計算機硬體和計算機應用的發展反過來又推動了進階語言的發展和變化。早期人們對進階語言還有些顧慮,主要是認為用它們編寫的程式的執行效率不如直接用彙編語言編寫的程式。經過多年的研究和開發,語言實作技術的發展已經基本消除了這方面的問題。今天絕大部分程式都是用進階語言開發的,隻有極少量的程式或程式部分是用彙編語言開發的。是以,今天人們在談論程式設計語言時,預設地就是指進階程式設計語言,本書後面也這樣做。
程式設計語言的要素
程式設計語言是人設計的一類語言,設計目标就是用于寫程式。一個完整的程式描述了一個計算過程,就像一個劇本描述一出話劇或一部電影的表演過程。計算機執行程式,與演員們執行劇本也有類似之處。當然,在這裡完全沒有臨場發揮,是以簡單得多。
上面的讨論實際上也揭示了程式的兩方面特征:一方面,一個程式是一段文本描述,完全是靜态的,就像一篇論文、一本小說,可以閱讀和了解,甚至可以修改重構。但另一方面,一個程式又蘊涵着一個執行過程、一段計算,這是一種動态的活動。這是程式的兩面性,程式設計的目标是實作其蘊涵的動态過程,但卻要用一段靜态文本去描述它。學習程式設計的一個重要方面,就是去了解這種靜态描述與動态過程的關系。
程式語言的一邊關聯着編寫程式的人們,另一邊關聯着執行程式的計算機,是以其形式必須滿足這兩個關聯方的需要:為了使計算機能夠處理和執行,程式設計語言必須有嚴格定義的形式。另一方面,由于程式需要人來寫,是以程式設計語言應該具有人比較容易使用和了解的形式,便于人閱讀、了解、參考,需要易讀、易了解、易學習、易使用。各種成功的進階語言,其設計都是在這兩種需要之間取得了較好的折中。
語言學的研究者們提出了語言的三個要素:文法、語義和語用。這種提法原本是針對人們在日常生活中使用的“自然語言”。作為一類人造語言,程式設計語言在文法和語義方面的情況比各種自然語言(如漢語、英語)更清晰準确:
文法是一套嚴格定義的規則,規定了一個程式設計語言中各種結構的形式,嚴格界定何種形式的描述是合法的程式或者合法的程式部分。不合乎語言文法的描述不是這種語言的程式,是以是完全沒意義的。
語義是另一套明确的規則,說明各種合法程式部分的實際意義,也就是說,計算機在處理(執行)這種程式部分時将會做什麼事情,完成什麼樣的計算。程式的語義是程式的内涵,也是人們在程式設計中最需要關心的問題。
語用并不是一套規定,而是人們在使用這種語言的過程中逐漸産生的技術積累。當然,由于都是為了描述計算,人們使用其他語言的已有技術也可能借鑒。此外,計算問題中也有許多常見的共性問題或相似問題,人們在處理一些情況的過程中開發了一些有用的方法,積累了很多經驗。這些都屬于語用的範疇。
本書将采用python語言作為讨論計算與程式設計的工作語言。由于上面這些情況,在後面章節中介紹python語言的一種結構時,通常也包括幾部分内容:(盡可能嚴格地)說明這種結構的文法形式,其結構和各個組成部分;(直接并可能通過示例)解釋這種結構産生的計算過程(操作的過程);通過一些例子說明這種結構可以(或者應該)如何使用。在介紹過一種結構之後,随後的執行個體中可能經常使用它們。讨論中還會經常出現不同結構的互相關系和對比,通過執行個體說明如何結合使用多種不同的結構。