• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天行健 君子當自強而不息

            【ZT】微軟架構師談編程語言發展(2)


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

            Charles:你這么一說,關于“函數型”編程,我馬上想到一個問題是:在現有基礎上再加一層必須考慮的抽象,實際上能不能增加程序員的生產率,是否真的有幫助?作為程序員,現在還要考慮“副作用”的問題。反正我現在用C#還是其他語言編程的時候,是不會像一個“函數型”程序員那樣考慮副作用的。
             
            Herb:往一個語言上增加更多的特性無法使其變簡單,這是個我們面臨的基本難題。
             
            Anders:作為一個語言設計師,對于編程語言,我們所能做的是——減緩新特性不斷累積的速度,從而避免最終的倒塌。我想說的是,你永遠不能收回某個特性。理論上,你可以收回某個特性,實際中,你不能這樣做,因為后果是若干代碼的崩潰,這行不通。
             
            Brian:是的,在從VB6到VB.NET的過程中,很多人已經感到飽受折磨了。是的,(微軟的)解決方案是說那(VB.NET)是個完全不同的語言。但是,我認為,“函數型”編程的概念已經出現了不短的時間,新畢業的程序員至少聽說過這個概念。他們在Python、JavaScript或者其他什么地方見過 lambda表達式,或者他們學過Scheme,總之這不是個沒聽說過的東西,因此,當他們在C#或其他的更傳統的編程語言,如VB或C++中看到這些概念的時候,他們并不會感到畏懼,因為他們了解這些概念的優點,他們知道這些東西如果用得正確,可以增加代碼的可組合性。你知道,傳統語言的可組合性靠的是程序員的自覺。在某些方面,Haskell編程比“命令型”編程要痛苦得多,然而反過來說,它也比“命令型”編程要簡單些,因為你不會把事情弄得一團糟。呵呵呵。
             
            Anders:這里我想插一句。我認為,在很大程度上,我希望我們在C#或VB上做的工作至少是——在很大程度上對“函數型”編程進行“去神秘化”。學院式的人總是傾向于讓事情聽起來比實際的要復雜,因為這樣一來就顯得他們自己比較聰明。“呃,我并不是針對任何人,但是,這里有不少符號代數和其他東西呢!(譯者注:音頻提高了,似乎在學某些人的語氣)”。當我向人們解釋lambda表示式時,大家是另一種感覺:“你的意思是他們就是函數?這有什么新鮮的?我們早就有函數了,lambda表達式只是些語法糖衣外殼吧?”是的,lambda表達式確實只是語法糖衣外殼,但這是種強有力的語法糖衣外殼,它使你能按照一種新的方式去思考問題,以前總是存在的一些語法噪音——必須聲明函數,進行委托,等等——就會逐漸減少,最終,一個全新層次的表達式列表會產生出來。這才是關鍵所在!圍繞著“函數型”編程還有非常多神秘,我希望我們能夠(在打破神秘上)有所突破……
             
            Herb:關于(Brian)說的教育問題,就是關于人們能夠在學校中學到的東西的說法,我不太同意。我真的希望情況確實如此,但是我認為缺乏證據,或者說除了 “Pascal熟悉者”之外,我們無法獲得更多。不管是在學校還是在今后的職業生涯中,人們都認為自己接觸了多種語言,因為他們用過C、C#、C++、 VB以及Pascal。但是,這些語言本質上是一樣的,是同一族的語言。人們并沒有接觸過APL——編程就象在解釋器外殼(譯者注:可以想象DOS的命令行)上敲東西;不熟悉Prolog——任何東西都是規則;不知道Lisp——所有的都是鏈表。只有當你深入了2到3種這些東西后,你才知道,并不是所有的東西都是命令。也許在你今后的職業生涯中用的都是命令型語言,正如我們大多數人一樣,但是,你不會對其他看待世界的觀點一無所知。某人從小到大,如果沒有離開過成長的城市,如紐約,超過一英里的話,會錯過不少有趣的地方,不管你是否想在其他地方住下來,你應該知道它們,體驗它們。
             
            Brian:呃,我覺得這是個漸變的過程,當然,我確實觀察到年輕一代程序員對于“函數型”編程有更好的認識了。你知道,10年,15年之前,如果你和人們談起 Scheme時,人們會感到不解地看著你,“什么?你在說什么?”。現在,人們聽說過了,他們見過“函數型”編程的關鍵字。而且,通過 JavaScript和Python,人們嘗試了“函數型”編程,也使得這些東西更加流行。我并不是說已經出現了巨大的變化,我是說逐漸的變化和更多的認知,人們不再象以前那樣看到這些東西就害怕了。
             
            Erik:也許JavaScript是這個世界上最……(譯者注:Brian一陣激動的插嘴,搞得Erik的話聽不清了)。我不確定當人們使用JavaScript時,他們是否意識到了這是一種把“函數”當作第一要素的語言。
             
            Brian:你可以在運行的時候創造它們(函數)……
             
            Charles:所有的東西都是一種類型,所有的東西都是對象,是吧?這是個有趣的語言。隨著整個互聯網的發展,你認為這種語言也應該有所進化……?
             
            Brian:這里的“所有的東西都是對象”,不是面向對象的意義。這里是從“任何東西都是關聯鏈表”的角度來說。現在我聽起來像一個老Lisp編程者(譯者注: Lisp基于鏈表),是吧?一個JavaScript的對象不像一個C#對象那樣——所有的內存排列都決定了,什么東西都靜態地決定了。這意味著所有的東西都可以添加、拿走,可以違反規則,它確實只意味著一個關聯鏈表。
             
            Anders:屬性包(我得意地笑)……
             
            Brian:是的,屬性包的說法更好!
             
            Erik:是的,值可以是函數、其他對象,或者是其他屬性包。
             
            Brian: JavaScript其實就是源自Lisp的Scheme。我又在說Scheme,因為我也許是這個屋子中唯一老到聽說過這個詞的人,呵呵!但是, Scheme有點類似于“上帝的Lisp”(譯者注:不知道是God’s Lisp, Guard’s Lisp還是什么別的,懂得有限,暫時按God’s Lisp處理,達人請指教),所有的噪音都被消除了,只剩下最基本的、最少的東西。JavaScript就是把這些東西帶到了前臺,披上件不那么可怕的外衣的結果。因為JavaScript看起來有點“C”的味道,你可以使用花括號!呵呵!
             
            (一陣亂哄哄)
             
            Charles:但是,JavaScript只是一種解釋性語言,而且,對開發者來說,用它編程也不是很有效率。JavaScript不像C#或VB,它沒有一種真正的面向對象語言所應該具備的IDE,以及你可以工作于其上的框架。
             
            Anders:呃,JavaScript是一種弱類型語言,或者說動態編程語言。人們經常把“編譯時”與語言的“類型強弱”相提并論。但是,這兩個概念其實是相互獨立的,是吧?你可以有一種“強類型”,然而在運行期編譯的語言,如果你真想要這樣的東西的話。但是,對我來說,我以前也講過,我非常樂于向那些喜歡“動態語言”、“腳本語言”的人指出,正是他們所醉心的那些地方會有問題。經常地,人們都理所當然地認為,如果沒有類型礙事,就不用聲明什么東西了,可以隨手就用,諸如此類。這樣干的時候你確實能夠更快地寫程序,然而,這里有一個陷阱:因為沒有類型,我們(編譯器)給你提供的幫助就少得多。當你寫“X.”時,對不起,“.”之后是什么我們沒法告訴你,我們沒有足夠的智能顯示給你,因為我們沒有任何辦法知道將發生什么。有時我們可以猜,但我們有可能猜錯,有時我們根本就一無所知,對吧?X或者其他參數,我們不知道將發生什么。我發現,有趣的是,我們在C#中進行的類型推論的工作,在許多方面都使得C#編程看起來更像動態語言,因為不會隨時看到類型,甚至壓根看不到。但是,類型在那里,靜態地在那里,這也意味著,我們仍然可以給你提供“語句完成”這樣的智能幫助。
             
            Charles:你是在說“var”關鍵字啰?
             
            Anders:“var”關鍵字只是個例子。光看這個關鍵字,似乎這是動態類型,然而,這是靜態類型。當你定義“var Blar”時,我們知道“Blar”是什么類型;當你寫“Blar.”時,“.”之后我們可以為你顯示出東西。
             
            Herb:我們(C++)中也在做一樣的事情。我有一個“int”類型的vector,我從該vector的頭部取出一個元素,我有什么必要再用 vector<int> 來聲明一個遍歷器?編譯器知道它是這個類型,編譯器能夠將類型正確加到變量上。這就是“var”類型干的事,你不必到處都寫出類型信息。這帶來了很大的好處,你可以書寫更好的“范型”代碼,以前那些東西是寫“范型”代碼的障礙。
             
            Anders:我想說的是,(如果有類型),我們就能在你寫代碼的時候給你許多的幫助,尤其在“智能感知”上我說是大實話。當今世界,如果你想把“智能感知”去掉,人們絕對會大叫“不!不!”,呵呵,這工具太有用了。但是,這里還有性能的問題。我是說,當編譯器知道類型時,它能夠為你生成更好的代碼。就是說,你會得到更好的執行效率。
             
            Erik:這里有件趣事。幾個月前我們有次編譯器XX(譯者注:沒聽清),參加者都反映說,“喔,你知道,F#是最好的動態語言!”要我來說的話,F#是擁有最先進的靜態類型系統的語言。當然,你不用寫任何的類型,因為編譯器幫你推斷了所有的類型。很有趣的是,人們經常混淆“不用寫類型”與“動態類型”。
             
            Brian:這些人可都是寫編譯器的職業程序員!這是在課程結束時,做調查時出的趣事:“你最喜歡的動態語言?”“F#!”
             
            Charles:但是(結巴了一陣,可能是震驚了),從開發人員的角度來看,動態類型是設計期的事吧?就我自己而言,如果我不必對任何東西進行強類型處理,我就會假設是動態類型。這是不是錯了?我是說,編譯器是怎么弄的?
             
            Anders: “動態類型”和“隱式類型”是有區別的。一種情況是,靠編譯器推斷出類型,但編譯器在編譯期就推斷出來了。另一種情況是,編譯器在編譯時一無所知,它假設這東西可以是任何類型,然后在運行時的適當時機,檢查到底是什么類型。后一種情況下,當你分發一個虛函數調用時,也許會使用一個查找表,或是別的什么東西,因為你壓根還不知道那是什么東西。前一種情況,根據到底是C#或是C++,你可以預先構造好虛表,準確地知道使用這個虛表的哪個內存地址來找到實際的東西,因為我已經計算好了。這就是預先有效地計算好了所有的東西。但是,人們往往錯誤理解(靜態類型)為,“我,我這個人本身,必須在任何時候親自手動寫出類型”實際上這并不必要,因為類型可以被推斷出來,如果你在一個地方知道了類型,你可以跟蹤程序邏輯,根據這里發生了什么,類型是如何變化的,從而知道在另一個地方類型是什么。如果你是個足夠聰明的編譯器,你應該可以做到這些,是吧?我們正開始把這種“聰明”加入到程序語言中。
             
            Brian: F#可能是這方面最好的例子。F#甚至欺騙了職業編譯器程序員!我認為人們真正喜歡的是快速的反饋。人們喜歡快速看到結果。在他們的意識中,他們把這種喜好和“動態”相混淆了。下面我具體講講:你輸入了一個函數,然后馬上敲入一行代碼來測試剛寫的函數,如果能夠正常工作,你就可以放心地忘掉它們(譯者注:指可以投入下面的其他工作),這是人使自己的“大腦堆棧”保持滿負荷運作的方式,是人的力量。歷史上,“動態語言”在使人以這種方式工作上卓有成效。你打開一個Lisp,你實際上得到的是一個Lisp的監聽器,你鍵入代碼,然后在相同的環境中立即測試代碼。但是,這實際上是個工具問題,與編譯器什么的完全沒有關系。你能夠使動態語言有一個好的IDE和交互的開發環境,你也能使靜態語言,如F#,擁有這樣的IDE和交互的開發環境。這就是Sam在F#演示上干的事情。他打開好長一段代碼,用鼠標選擇它們,用“GO”按鈕來執行;然后他打開另外一段代碼,再用鼠標選擇,再按“GO”來執行。所有的人都以為這是動態解釋執行的。實際上,這是靜態的,完全編譯的。這就是欺騙行家的方法。呵呵(我得意地笑……)。但這確實是人們喜歡的東西。大家都喜歡能提供“不斷反饋”的好工具,或者是“交互式開發環境”,無論你管這叫什么。只要你能夠隨時寫代碼并且測試,你就不必寫一大堆代碼后再測試。你會這樣想,“嘿,我寫了個叫‘RandomDouble’的函數,讓我把它敲進去看看是否能工作”。如果能正常工作,你就可以在進一步的Debugging前把它忘掉(去做別的工作)。


            posted on 2007-09-11 03:13 lovedday 閱讀(325) 評論(0)  編輯 收藏 引用 所屬分類: ▲ Software Program

            公告

            導航

            統計

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關鏈接

            搜索

            最新評論

            欧美精品国产综合久久| 狠狠88综合久久久久综合网| 欧美日韩精品久久久免费观看| 成人国内精品久久久久一区| 久久免费精品视频| 久久久精品人妻一区二区三区蜜桃 | 国产亚洲精品久久久久秋霞| 狠狠色婷婷综合天天久久丁香 | 欧美伊人久久大香线蕉综合 | 18岁日韩内射颜射午夜久久成人| 色综合久久中文字幕综合网| 伊人久久大香线蕉无码麻豆| 国产精品欧美久久久天天影视| 亚洲欧美成人综合久久久| 久久精品一区二区三区不卡| 2021最新久久久视精品爱| 国产精品熟女福利久久AV| A狠狠久久蜜臀婷色中文网| 伊人久久五月天| 久久亚洲精品无码观看不卡| 久久国产亚洲精品麻豆| 久久久久亚洲精品无码蜜桃 | 亚洲性久久久影院| 精品久久人人爽天天玩人人妻| 精品国产乱码久久久久久1区2区| 久久久久久精品免费免费自慰| 久久久久久亚洲精品无码| 久久丫精品国产亚洲av不卡| 2021国内久久精品| 久久综合久久综合亚洲| 伊人久久大香线蕉无码麻豆| 性做久久久久久久久久久| 日韩十八禁一区二区久久| 久久精品国产一区二区| 久久狠狠一本精品综合网| 国产精品久久久久久久午夜片| 久久精品三级视频| 久久人搡人人玩人妻精品首页| 亚洲乱码日产精品a级毛片久久 | 无码八A片人妻少妇久久| 久久久久国产精品三级网|