2. 自然語言和形式語言

自然語言(Natural Language)就是人類講的語言,比如漢語、英語和法語。這類語言不是人為設計(雖然有人試圖強加一些規則)而是自然進化的。形式語言(Formal Language)是為了特定應用而人為設計的語言。例如數學家用的數字和運算符號、化學家用的分子式等。編程語言也是一種形式語言,是專門設計用來表達計算過程的形式語言。

形式語言有嚴格的語法(Syntax)規則,例如,3+3=6是一個語法正確的數學等式,而3=+6$則不是,H2O是一個正確的分子式,而2Zz則不是。語法規則是由符號(Token)和結構(Structure)的規則所組成的。Token的概念相當於自然語言中的單詞和標點、數學式中的數和運算符、化學分子式中的元素名和數字,例如3=+6$的問題之一在於$不是一個合法的數也不是一個事先定義好的運算符,而2Zz的問題之一在於沒有一種元素的縮寫是Zz。結構是指Token的排列方式,3=+6$還有一個結構上的錯誤,雖然加號和等號都是合法的運算符,但是不能在等號之後緊跟加號,而2Zz的另一個問題在於分子式中必須把下標寫在化學元素名稱之後而不是前面。關於Token的規則稱為詞法(Lexical)規則,而關於結構的規則稱為語法(Grammar)規則[1]

當閲讀一個自然語言的句子或者一種形式語言的語句時,你不僅要搞清楚每個詞(Token)是什麼意思,而且必須搞清楚整個句子的結構是什麼樣的(在自然語言中你只是沒有意識到,但確實這樣做了,尤其是在讀外語時你肯定也意識到了)。這個分析句子結構的過程稱為解析(Parse)。例如,當你聽到“The other shoe fell.”這個句子時,你理解the other shoe是主語而fell是謂語動詞,一旦解析完成,你就搞懂了句子的意思,如果知道shoe是什麼東西,fall意味着什麼,這句話是在什麼上下文(Context)中說的,你還能理解這個句子主要暗示的內容,這些都屬於語義(Semantic)的範疇。

雖然形式語言和自然語言有很多共同之處,包括Token、結構和語義,但是也有很多不一樣的地方。

歧義性(Ambiguity)

自然語言充滿歧義,人們通過上下文的線索和自己的常識來解決這個問題。形式語言的設計要求是清晰的、毫無歧義的,這意味着每個語句都必須有確切的含義而不管上下文如何。

冗餘性(Redundancy)

為了消除歧義減少誤解,自然語言引入了相當多的冗餘。結果是自然語言經常說得囉裡囉嗦,而形式語言則更加緊湊,極少有冗餘。

與字面意思的一致性

自然語言充斥着成語和隱喻(Metaphor),我在某種場合下說“The other shoe fell”,可能並不是說誰的鞋掉了。而形式語言中字面(Literal)意思基本上就是真實意思,也會有一些例外,例如下一章要講的C語言轉義序列,但即使有例外也會明確規定哪些字面意思不是真實意思,它們所表示的真實意思又是什麼。

說自然語言長大的人(實際上沒有人例外),往往有一個適應形式語言的困難過程。某種意義上,形式語言和自然語言之間的不同正像詩歌和說明文的區別,當然,前者之間的區別比後者更明顯:

詩歌

詞語的發音和意思一樣重要,全詩作為一個整體創造出一種效果或者表達一種感情。歧義和非字面意思不僅是常見的而且是刻意使用的。

說明文

詞語的字面意思顯得更重要,並且結構能傳達更多的信息。詩歌只能看一個整體,而說明文更適合逐字句分析,但仍然充滿歧義。

程序

計算機程序是毫無歧義的,字面和本意高度一致,能夠完全通過對Token和結構的分析加以理解。

現在給出一些關於閲讀程序(包括其它形式語言)的建議。首先請記住形式語言遠比自然語言緊湊,所以要多花點時間來讀。其次,結構很重要,從上到下從左到右讀往往不是一個好辦法,而應該學會在大腦裡解析:識別Token,分解結構。最後,請記住細節的影響,諸如拼寫錯誤和標點錯誤這些在自然語言中可以忽略的小毛病會把形式語言搞得面目全非。



[1] 很不幸,Syntax和Grammar通常都翻譯成“語法”,這讓初學者非常混亂,Syntax的含義其實包含了Lexical和Grammar的規則,還包含一部分語義的規則,例如在C程序中變數應先聲明後使用。即使在英文的文獻中Syntax和Grammar也常混用,在有些文獻中Syntax的含義不包括Lexical規則,只要注意上下文就不會誤解。另外,本書在翻譯容易引起混淆的時候通常直接用英文名稱,例如Token沒有十分好的翻譯,直接用英文名稱。