小tao給我找了一個(gè)非常好的題目:

我承認(rèn)以前沒有考慮到這個(gè)問題,因?yàn)槲乙詾樽非蟾拍钜恢滦允且环N不言自明的天性。那么為什么要一致性很重要呢?我有這樣一些想法。
1. 復(fù)雜性
概念不一致產(chǎn)生首先產(chǎn)生的一個(gè)惡果就是復(fù)雜性,這里我將舉兩個(gè)例子。
第一個(gè)關(guān)于Lisp的。Lisp本身具有一個(gè)很一致很簡(jiǎn)單的計(jì)算模型——λ 演算。在這個(gè)計(jì)算模型中,基本元素是函數(shù),λ運(yùn)算符,·運(yùn)算符。語義也是簡(jiǎn)單明確的,lambda運(yùn)算符提取出函數(shù)中的自由變量,然后再由apply對(duì)自由變量賦值。整個(gè)計(jì)算過程就是函數(shù)(符號(hào))求值的過程。例如對(duì)于函數(shù)x + y,我們可以這樣來求值。





由于Lisp多少可以認(rèn)為是λ 演算的一種實(shí)現(xiàn),我們可以類似寫出Lisp代碼


或者更加簡(jiǎn)單的寫為


所有在Lisp中的程序,我們都可以用一種一致的概念來表達(dá),就是符號(hào)求值,我們對(duì)一個(gè)符號(hào)應(yīng)用一些值,然后這個(gè)符號(hào)完成計(jì)算并把結(jié)構(gòu)返回給我們,在計(jì)算的過程中,符號(hào)對(duì)外部環(huán)境沒有任何破壞和依賴。但是Lisp中引入了賦值,于是存在一些符號(hào),不僅僅是來計(jì)算,同時(shí)他們還能改變環(huán)境。




這個(gè)函數(shù)不僅僅求x + y的值,同時(shí)修改了符號(hào)Z的值。賦值的引入破壞了函數(shù)只求值而不影響環(huán)境這個(gè)概念的一致性。于是我們不得不尋找一個(gè)更加復(fù)雜的也更加混亂的計(jì)算模型,來代替簡(jiǎn)單優(yōu)雅的λ 演算。于是不一致的概念帶來了思維上的復(fù)雜性(不過Lisp中的概念不一致除了產(chǎn)生了復(fù)雜之外,還激發(fā)了人們對(duì)于簡(jiǎn)單計(jì)算模型的向往從而產(chǎn)生了函數(shù)式編程風(fēng)格,這也是我最愛的編程風(fēng)格之一)。
概念不一致帶來的復(fù)雜性距離我們最近的應(yīng)該是Java中的簡(jiǎn)單類型,Java本身是一個(gè)單根的面向?qū)ο笳Z言,從概念上講一切都應(yīng)該是對(duì)象,而且由于性能考慮而出現(xiàn)的簡(jiǎn)單類型,引入了代數(shù)性的世界觀的同時(shí),破壞了面向?qū)ο蟮囊恢赂拍?。Java中雖然有包裝類來做補(bǔ)償,但是仍然不能彌補(bǔ)概念上的斷裂。我們可以用

來代表對(duì)象概念中的3,但是
3 + 4 * 5
不能對(duì)等的翻譯為:

簡(jiǎn)單類型具有的運(yùn)算符和對(duì)象類型的消息發(fā)送概念上是不一致的。雖然我們可以在Java 5中使用上述的代碼,但是Java 5的Auto-Boxing更多的把對(duì)象類型當(dāng)作簡(jiǎn)單類型進(jìn)行數(shù)據(jù)運(yùn)算,而不是像C++中的運(yùn)算符重載一樣把數(shù)據(jù)運(yùn)算當(dāng)作一種特殊消息傳遞,雖然語法上有相似的功能,但是概念上大異其趣,對(duì)于我這個(gè)OO分子而言,Java 5的Auto-Boxing實(shí)在是惡心到不行。同時(shí)簡(jiǎn)單類型和對(duì)象類型在賦值語義和存儲(chǔ)模型上也存在很大的不一致,這種不一致性在使用Collection API的時(shí)候帶來了一些復(fù)雜度。(還記得Commons Collection里那些Primitive Collection吧?)
2.副作用
概念不一致產(chǎn)生的第二個(gè)惡果就是副作用,我大概想了一下都有哪些可能的副作用,結(jié)果讓我很寒,我能想到的副作用,大多數(shù)是由于在另一種模型中引入了馮語言的因素從而造成了概念上的不一致而引起的。其中最為人知的....還是賦值在函數(shù)式編程中的副作用...這個(gè)在函數(shù)式編程社區(qū)有很廣泛的討論,我只說一點(diǎn),為什么命令語言是有害的。
馮語言或者說命令式語言主要用于刻畫對(duì)計(jì)算機(jī)操作的序列,并不關(guān)心序列的內(nèi)在關(guān)系。也就是說,我們可以把一些完全沒有聯(lián)系的指令寫在一起。因此馮語言在語義上毫無建樹,同時(shí)在抽象上也止步于子程序(一砣指令和另一砣指令)。馮語言具有很強(qiáng)的時(shí)間耦合性在存儲(chǔ)上也強(qiáng)烈的傾向于線性存儲(chǔ)。目前大多數(shù)難處理的問題,可以歸結(jié)為計(jì)算模型和操作語義的不一致,甚至有些學(xué)者認(rèn)為是馮結(jié)構(gòu)嚴(yán)重制約了計(jì)算機(jī)的發(fā)展。因此馮語言被函數(shù)社區(qū)看作一個(gè)很危險(xiǎn)的副作用,極力避免之。
概念的不一致產(chǎn)生的副作用在混血的OO語言中也很明顯,尤其是在命令式語言中加入面向?qū)ο髾C(jī)制,而且使用面向?qū)ο笞鳛轭愋拖到y(tǒng)的擴(kuò)展,使用過程式的方法來控制流程。過程和對(duì)象的不一致本身就給了程序員一種暗示,你可以使用對(duì)象技術(shù)來構(gòu)造類型系統(tǒng),然后使用過程的方法來操作他。明顯的副作用們很容易使用過程化程序,從而使得對(duì)象帶來的好處被很大的削弱了(當(dāng)然我們有重構(gòu)來彌補(bǔ)這個(gè)錯(cuò)誤),比如下面一個(gè)例子,我們很容易從寫出下面的代碼:

2

3

4

5

6

而不是

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

因?yàn)榇嬖谶^程性的關(guān)鍵字if, while,處于方便的考慮,我們會(huì)寫出第一種風(fēng)格的代碼,而考慮到易于維護(hù),我們應(yīng)該寫第二種風(fēng)格的代碼。存在兩種不一致的書寫代碼的風(fēng)格,這個(gè)時(shí)候,副作用取決于使用的語言O(shè)O的程度,比如在C++里更容易寫出第一種風(fēng)格的代碼,而在Ruby和Smalltalk中,更容易寫出第二種風(fēng)格的代碼。
3.遞歸的構(gòu)造軟件
這個(gè)雖然跟概念一致有關(guān),但是一個(gè)更大的主題,待續(xù)吧。
4.優(yōu)雅,美感和無名品質(zhì)
概念的一致性會(huì)產(chǎn)生一種優(yōu)雅的美感,我覺得我們都有這種感覺,如果我們能用一種一致的容易理解且統(tǒng)一的方式來處理多種不同的復(fù)雜的問題,那么我們就會(huì)覺得這種方法很優(yōu)雅,也很具有美感。類比物理中的牛頓定律,開普勒定律,麥克斯韋方程,都是這種簡(jiǎn)單一致而解決復(fù)雜問題的完美示例。我們更容易感覺到一致的感念產(chǎn)生的美感,而不一致的概念往往很難令我欣賞。或許無名品質(zhì)是我對(duì)一致的概念的一種模糊的審美吧。
我大抵能想到的就這么多,不知小tao是否滿意我的答卷。
這句說的實(shí)在是太動(dòng)聽了,至理名言啊
語言要是沒有數(shù)學(xué)上的一致性
終究會(huì)讓人討厭的
不過說是帶有算術(shù)的公理系統(tǒng)不能同時(shí)保證一致性和完備性
以上這句我不怎么懂,好像是歌德爾定理哈