Herb:我想,我們有必要在“函數(shù)型”編程領(lǐng)域做一個(gè)進(jìn)一步區(qū)分,將其劃分成兩個(gè)部分。我非常同意Anders和Erik的意見(jiàn)。我不太同意的是這樣的措辭:我們之所以繼續(xù)使用“命令型”編程語(yǔ)言,是因?yàn)檫@是大家目前所能理解的;通用程序員目前的工作并未取得巨大的成功;市場(chǎng)對(duì)于“所有的東西都是表達(dá)式,所有的語(yǔ)言都應(yīng)該是表達(dá)式類(lèi)型的語(yǔ)言”這樣的理念已經(jīng)非常接受了;“函數(shù)型”語(yǔ)言是“串行執(zhí)行”的好藥方。我們要想使“函數(shù)型”語(yǔ)言運(yùn)轉(zhuǎn)良好,關(guān)鍵的并不是處理好基本的表達(dá)式問(wèn)題,而是處理好lambda表達(dá)式和副作用的問(wèn)題,關(guān)鍵是能夠?qū)⒈磉_(dá)式作為第一級(jí)的編程要素來(lái)使用——LINQ也是最近才在做,關(guān)鍵是能夠指出lambda表達(dá)式和Closure(譯者注:函數(shù)型編程語(yǔ)言中的一個(gè)概念,可以方便地組合函數(shù),返回函數(shù))的副作用。實(shí)際上,最后這點(diǎn)目前是缺失的(Anders也附和著:對(duì),對(duì))。這些東西在“命令型”語(yǔ)言中也是要處理的東西。我為什么提這些?因?yàn)槲矣X(jué)得說(shuō)“函數(shù)型”語(yǔ)言是方向,目前的“命令型”語(yǔ)言不夠好,因此是垃圾,必須要拋在腦后,全面采用“函數(shù)型”語(yǔ)言這樣的說(shuō)法不對(duì)(譯者注:呵呵,對(duì)Anders的說(shuō)法有點(diǎn)急了,畢竟是泡在C++上,對(duì)C++有感情的人)。我認(rèn)為,對(duì)于“函數(shù)型”語(yǔ)言能夠幫助程序員完成哪些工作,目前還不太明了。比如,能夠用它寫(xiě)通用代碼嗎?能夠用它系統(tǒng)級(jí)代碼嗎?當(dāng)然,“函數(shù)型”語(yǔ)言有不少我們能夠應(yīng)用的好東西,比如lambda表達(dá)式,比如Closure,C#借鑒了,C++也在借鑒,這些語(yǔ)言因此增色不少。關(guān)于“函數(shù)型”語(yǔ)言還有另一個(gè)問(wèn)題,那就是有兩種類(lèi)型的“函數(shù)型”語(yǔ)言,一種是沒(méi)有副作用的,因此就沒(méi)有共享的易變的狀態(tài)的問(wèn)題;一種是人人都在使用的,對(duì)吧(譯者注:顯然Herb認(rèn)為“沒(méi)有副作用”的理想情況是不太可能的)?因?yàn)槟悴惶赡苷f(shuō),“瞧,我是完全并發(fā)安全的,因?yàn)槊看挝覐腦X(譯者注:聽(tīng)不清)向量中得到一個(gè)拷貝,或者我使用XX(譯者注:聽(tīng)不清)元素的時(shí)候,我都是取得一個(gè)拷貝”。確實(shí)不錯(cuò),這里是沒(méi)有共享的易變的狀態(tài),但是是否能夠完全并發(fā)安全則不一定。
Anders:是的。我的意思是,在類(lèi)似C#或VB這樣的“命令型”編程語(yǔ)言中加入“函數(shù)型”結(jié)構(gòu),能給我們提供“以函數(shù)型風(fēng)格”寫(xiě)庫(kù)的能力,從而我們就能夠非常明確地說(shuō),如果你能保證傳入的lambda表達(dá)式是純粹的函數(shù),我們就能保證正確地把它分散到若干個(gè)線程或者CPU上,最后把它綜合起來(lái),給你一個(gè)正確的結(jié)果,我們能夠保證代碼運(yùn)行得更快,同時(shí)你還不用作任何編碼上的修改。如果你在寫(xiě)一個(gè)大大的For循環(huán),我們永遠(yuǎn)都不可能保證做到前面所說(shuō)的,此時(shí),“函數(shù)型”編程能夠提供給你的是一系列表達(dá)式,再加上“把代碼當(dāng)作參數(shù)傳遞”,“類(lèi)型推論和泛型編程可以正確地綁定所有的類(lèi)型”這些特性,這樣你就能更方便地編寫(xiě)“可組合的算法塊”。
Charles:這樣一來(lái)不就削弱了抽象嗎(譯者注:Charles可能想的是程序員不需要再關(guān)心“可組合性”,語(yǔ)言和運(yùn)行庫(kù)應(yīng)該保證這件事,而現(xiàn)在聽(tīng)起來(lái)并非如此)?
Herb:呃,我很同意Anders的意見(jiàn),我想指出的是,當(dāng)前所有的語(yǔ)言都有意不保證 “沒(méi)有副作用”。之所以如此的原因是,除非所有的語(yǔ)言都添加一些機(jī)制讓程序員可以清除副作用,我們這些做語(yǔ)言的人不敢打這個(gè)包票。但是,添加這樣的機(jī)制涉及到眾多參加者,大家一起思考、討論什么是的方法的過(guò)程會(huì)很漫長(zhǎng)。我們所做的是相信程序員,因?yàn)槲覀冏约翰恢?。然而,程序員在很多情況下也不知道,因?yàn)樗麑?xiě)的函數(shù)要調(diào)用其他的庫(kù)。這里“可組合性”又浮上水面了,程序員根本不知道他用的庫(kù)有怎樣的副作用。一般說(shuō)來(lái)程序員會(huì)再增加一層間接性,但是問(wèn)題依然存在,沒(méi)有人能夠清楚地知道副作用,除非他擁有涉及到的所有的代碼,這就是難題所在。上面這些討論對(duì)“鎖”也適用,因?yàn)椤版i”也是個(gè)全局問(wèn)題,對(duì)于“可操作性”是個(gè)障礙。
Brian:(譯者注:在Herb說(shuō)話的時(shí)候已經(jīng)很著急地想說(shuō)了幾次)在這點(diǎn)上Haskell做得很好,Haskell是“永遠(yuǎn)沒(méi)有副作用”的范例。
Erik:是的,但做到這點(diǎn)的過(guò)程也是痛苦的,因?yàn)椴⒎撬械那闆r都一目了然。一旦你的(庫(kù))代碼有副作用,而且因此使程序員的代碼必須按照某種順序執(zhí)行(因?yàn)楦弊饔玫年P(guān)系,該程序必須先干某事,再干某事),某種意義上你在用匯編語(yǔ)言編寫(xiě)東西,因?yàn)槌绦騿T將不再能用“表達(dá)式+表達(dá)式”的方式來(lái)寫(xiě)代碼,他必須決定先對(duì)某個(gè)表達(dá)式求值,再對(duì)另一表達(dá)式求值,再把值加起來(lái)。因此我認(rèn)為我們?cè)谶@點(diǎn)上干得還是不夠漂亮。
Brian:現(xiàn)在,我們?cè)凇傲鲙?kù)”上有例子。好消息是,我們已經(jīng)有Haskell向你展示如何以“可行性”方面的代價(jià),換來(lái)用絕對(duì)純粹的方式來(lái)做事。當(dāng)然,除Haskell外我們有各種“雜牌”語(yǔ)言。呵呵!
(眾人均樂(lè))
Charles:這是個(gè)供研究的語(yǔ)言嗎?
Brian:是的,我們將它設(shè)計(jì)為供研究用。
Anders:沒(méi)有純粹的好或壞,我認(rèn)為,雖然進(jìn)展緩慢,我們?nèi)匀豢斓揭粋€(gè)令人滿(mǎn)意的中間點(diǎn)了。我完全同意說(shuō),如果我們確實(shí)能夠保證函數(shù)的純粹性,生活將會(huì)非常美好。最終我們必須要做到。
Brian:在研究領(lǐng)域,大概有20多項(xiàng)工作與此有關(guān)——契約語(yǔ)言,契約和限制,等等。
Erik:但是,不少的副作用也并非壞事,如果我的函數(shù)使用了一個(gè)局部變量,這就是使用了一個(gè)狀態(tài),但是,函數(shù)本身還是純粹的。如果你想要完全避免副作用,我覺(jué)得會(huì)非常困難,一些東西可以是局部不純粹而整體純粹的。
Herb:回過(guò)頭,讓我們從整體上看看“可組合性”。讓我吃驚的一件事是,很多時(shí)候,人們甚至都沒(méi)有意識(shí)到這是個(gè)問(wèn)題。他們并沒(méi)有意識(shí)到自己實(shí)際上經(jīng)常碰到這個(gè)問(wèn)題。整個(gè)軟件工業(yè),整個(gè)世界其實(shí)已經(jīng)基于可組合的軟件了。在硬件會(huì)議上,我經(jīng)常對(duì)硬件公司提到的是(呵呵,通常此時(shí)我都是在轟擊硬件工業(yè),但是軟件業(yè)也有同樣的問(wèn)題):硬件的并發(fā)問(wèn)題被仔細(xì)地探索過(guò)了,而且,當(dāng)前消除共享易變狀態(tài)的辦法就是“鎖”;但是,鎖是全局的,是一種全局資源,不能被組合;“被鎖”是經(jīng)常發(fā)生的事情,而擁有一個(gè)鎖時(shí),我還能調(diào)用任何其他的未知的代碼,這就破壞了“可組合性”。說(shuō)到這里,有的聽(tīng)者往往一臉茫然:這有什么問(wèn)題嗎?我于是指出,好的,你們是否上網(wǎng)下載別人剛剛發(fā)布的,自己喜歡的新軟件,比如,某個(gè)瀏覽器,3個(gè)插件,然后就用呢?大家回答:是啊。于是我再指出,你們是否意識(shí)到了,當(dāng)你們這樣做時(shí),經(jīng)常地,這些軟件都是第一次在最終用戶(hù)的機(jī)器上被組合,被使用?既然如此,你們?cè)趺纯赡軐?duì)其進(jìn)行測(cè)試?這時(shí),屋子里有百分之十的人會(huì)露出恍然的表情,因?yàn)榇饲八麄儧](méi)有想過(guò)這個(gè)問(wèn)題:這些軟件是第一次在最終用戶(hù)的機(jī)器上被組合,我們?cè)趺催M(jìn)行測(cè)試?正因如此,“可組合性”是更加重要的一個(gè)問(wèn)題。更不用說(shuō)我們現(xiàn)在有AJAX,應(yīng)用程序,以及眾多的其他插件經(jīng)常被下載,而且被要求在同一個(gè)用戶(hù)界面中協(xié)調(diào)工作。
Anders:是的。我的意思是,在類(lèi)似C#或VB這樣的“命令型”編程語(yǔ)言中加入“函數(shù)型”結(jié)構(gòu),能給我們提供“以函數(shù)型風(fēng)格”寫(xiě)庫(kù)的能力,從而我們就能夠非常明確地說(shuō),如果你能保證傳入的lambda表達(dá)式是純粹的函數(shù),我們就能保證正確地把它分散到若干個(gè)線程或者CPU上,最后把它綜合起來(lái),給你一個(gè)正確的結(jié)果,我們能夠保證代碼運(yùn)行得更快,同時(shí)你還不用作任何編碼上的修改。如果你在寫(xiě)一個(gè)大大的For循環(huán),我們永遠(yuǎn)都不可能保證做到前面所說(shuō)的,此時(shí),“函數(shù)型”編程能夠提供給你的是一系列表達(dá)式,再加上“把代碼當(dāng)作參數(shù)傳遞”,“類(lèi)型推論和泛型編程可以正確地綁定所有的類(lèi)型”這些特性,這樣你就能更方便地編寫(xiě)“可組合的算法塊”。
Charles:這樣一來(lái)不就削弱了抽象嗎(譯者注:Charles可能想的是程序員不需要再關(guān)心“可組合性”,語(yǔ)言和運(yùn)行庫(kù)應(yīng)該保證這件事,而現(xiàn)在聽(tīng)起來(lái)并非如此)?
Herb:呃,我很同意Anders的意見(jiàn),我想指出的是,當(dāng)前所有的語(yǔ)言都有意不保證 “沒(méi)有副作用”。之所以如此的原因是,除非所有的語(yǔ)言都添加一些機(jī)制讓程序員可以清除副作用,我們這些做語(yǔ)言的人不敢打這個(gè)包票。但是,添加這樣的機(jī)制涉及到眾多參加者,大家一起思考、討論什么是的方法的過(guò)程會(huì)很漫長(zhǎng)。我們所做的是相信程序員,因?yàn)槲覀冏约翰恢?。然而,程序員在很多情況下也不知道,因?yàn)樗麑?xiě)的函數(shù)要調(diào)用其他的庫(kù)。這里“可組合性”又浮上水面了,程序員根本不知道他用的庫(kù)有怎樣的副作用。一般說(shuō)來(lái)程序員會(huì)再增加一層間接性,但是問(wèn)題依然存在,沒(méi)有人能夠清楚地知道副作用,除非他擁有涉及到的所有的代碼,這就是難題所在。上面這些討論對(duì)“鎖”也適用,因?yàn)椤版i”也是個(gè)全局問(wèn)題,對(duì)于“可操作性”是個(gè)障礙。
Brian:(譯者注:在Herb說(shuō)話的時(shí)候已經(jīng)很著急地想說(shuō)了幾次)在這點(diǎn)上Haskell做得很好,Haskell是“永遠(yuǎn)沒(méi)有副作用”的范例。
Erik:是的,但做到這點(diǎn)的過(guò)程也是痛苦的,因?yàn)椴⒎撬械那闆r都一目了然。一旦你的(庫(kù))代碼有副作用,而且因此使程序員的代碼必須按照某種順序執(zhí)行(因?yàn)楦弊饔玫年P(guān)系,該程序必須先干某事,再干某事),某種意義上你在用匯編語(yǔ)言編寫(xiě)東西,因?yàn)槌绦騿T將不再能用“表達(dá)式+表達(dá)式”的方式來(lái)寫(xiě)代碼,他必須決定先對(duì)某個(gè)表達(dá)式求值,再對(duì)另一表達(dá)式求值,再把值加起來(lái)。因此我認(rèn)為我們?cè)谶@點(diǎn)上干得還是不夠漂亮。
Brian:現(xiàn)在,我們?cè)凇傲鲙?kù)”上有例子。好消息是,我們已經(jīng)有Haskell向你展示如何以“可行性”方面的代價(jià),換來(lái)用絕對(duì)純粹的方式來(lái)做事。當(dāng)然,除Haskell外我們有各種“雜牌”語(yǔ)言。呵呵!
(眾人均樂(lè))
Charles:這是個(gè)供研究的語(yǔ)言嗎?
Brian:是的,我們將它設(shè)計(jì)為供研究用。
Anders:沒(méi)有純粹的好或壞,我認(rèn)為,雖然進(jìn)展緩慢,我們?nèi)匀豢斓揭粋€(gè)令人滿(mǎn)意的中間點(diǎn)了。我完全同意說(shuō),如果我們確實(shí)能夠保證函數(shù)的純粹性,生活將會(huì)非常美好。最終我們必須要做到。
Brian:在研究領(lǐng)域,大概有20多項(xiàng)工作與此有關(guān)——契約語(yǔ)言,契約和限制,等等。
Erik:但是,不少的副作用也并非壞事,如果我的函數(shù)使用了一個(gè)局部變量,這就是使用了一個(gè)狀態(tài),但是,函數(shù)本身還是純粹的。如果你想要完全避免副作用,我覺(jué)得會(huì)非常困難,一些東西可以是局部不純粹而整體純粹的。
Herb:回過(guò)頭,讓我們從整體上看看“可組合性”。讓我吃驚的一件事是,很多時(shí)候,人們甚至都沒(méi)有意識(shí)到這是個(gè)問(wèn)題。他們并沒(méi)有意識(shí)到自己實(shí)際上經(jīng)常碰到這個(gè)問(wèn)題。整個(gè)軟件工業(yè),整個(gè)世界其實(shí)已經(jīng)基于可組合的軟件了。在硬件會(huì)議上,我經(jīng)常對(duì)硬件公司提到的是(呵呵,通常此時(shí)我都是在轟擊硬件工業(yè),但是軟件業(yè)也有同樣的問(wèn)題):硬件的并發(fā)問(wèn)題被仔細(xì)地探索過(guò)了,而且,當(dāng)前消除共享易變狀態(tài)的辦法就是“鎖”;但是,鎖是全局的,是一種全局資源,不能被組合;“被鎖”是經(jīng)常發(fā)生的事情,而擁有一個(gè)鎖時(shí),我還能調(diào)用任何其他的未知的代碼,這就破壞了“可組合性”。說(shuō)到這里,有的聽(tīng)者往往一臉茫然:這有什么問(wèn)題嗎?我于是指出,好的,你們是否上網(wǎng)下載別人剛剛發(fā)布的,自己喜歡的新軟件,比如,某個(gè)瀏覽器,3個(gè)插件,然后就用呢?大家回答:是啊。于是我再指出,你們是否意識(shí)到了,當(dāng)你們這樣做時(shí),經(jīng)常地,這些軟件都是第一次在最終用戶(hù)的機(jī)器上被組合,被使用?既然如此,你們?cè)趺纯赡軐?duì)其進(jìn)行測(cè)試?這時(shí),屋子里有百分之十的人會(huì)露出恍然的表情,因?yàn)榇饲八麄儧](méi)有想過(guò)這個(gè)問(wèn)題:這些軟件是第一次在最終用戶(hù)的機(jī)器上被組合,我們?cè)趺催M(jìn)行測(cè)試?正因如此,“可組合性”是更加重要的一個(gè)問(wèn)題。更不用說(shuō)我們現(xiàn)在有AJAX,應(yīng)用程序,以及眾多的其他插件經(jīng)常被下載,而且被要求在同一個(gè)用戶(hù)界面中協(xié)調(diào)工作。