<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    冒號課堂§3.2:超級范式

    冒號課堂

    第三課 常用范式(2)

     

     3.2超級范式——提升語言的級別

    智能繁衍:機器人生產(chǎn)機器人                                            ——題記

     

    關(guān)鍵詞:編程范式,模板元編程,元編程,語言導(dǎo)向式編程,產(chǎn)生式編程

    摘要:元編程簡談

     
    提問

    • 什么是元編程?它與通常的編程有何不同?
    • 元編程有何用處?它有哪些應(yīng)用?
    • 相比自編的元程序,用IDE自動生成的代碼有什么缺陷?
    • 語言導(dǎo)向式編程有何優(yōu)點?它與元編程有何關(guān)系?
    • 元編程與產(chǎn)生式編程有何異同?
    • 為什么說元程序是一種最高級的程序?


     講解

    問號忽然想起一事,問道:“有一本名為《C++模版元編程》的書,既然提到了模板,想來也屬于泛型編程吧?”

    冒號答道:“模板元編程Template Metaprogramming,與泛型編程密切相關(guān)但自成一派,隸屬于另一種編程范式——元編程Metaprogramming),簡稱MP。此處的前綴‘meta-’常譯作‘元’,其實就是‘超級’、‘行而上’的意思。比如,元數(shù)據(jù)Metadata)是關(guān)于數(shù)據(jù)的數(shù)據(jù),元對象Metaobject)是關(guān)于對象的對象,依此類推,元編程自然是關(guān)于程序的程序,或者說是編寫、操縱程序的程序。”

    嘆號皺著眉:“聽著有點繞。”

    冒號投影出另一段代碼——

    C++(元編程):

    template <int N>

    struct factorial

    {

         enum { value = N * factorial<N - 1>::value };

    };

    template <>                // 特化specialization

    struct factorial<0>    // 遞歸中止

    {

         enum { value = 1 };

    };

    void main()

    {

        cout << factorial<5>::value << endl; // 等價于 cout << 120 << endl;

    }

    “以上用模板元編程實現(xiàn)了階乘運算。”冒號講解道,“與前面三種核心范式的階乘實現(xiàn)有著根本的不同:這里階乘的值是在編譯時而非運行時計算出來的。換句話說,這段代碼以模板形式通過編譯器生成了新的代碼,并在編譯期間獲得執(zhí)行。”

    嘆號大惑不解:“這又說明什么呢?”

    冒號并不直接回答:“假設(shè)你需要批量處理用戶文檔,其格式結(jié)構(gòu)預(yù)先給定,但既不像CSV(逗號分隔)那么簡單,也不像XML那么標準,并且用戶隨時可能改變格式標準,請問如何設(shè)計這段程序?”

    嘆號略一思索,便回答:“三大模塊:閱讀器讀出輸入文檔,解析器按照格式標準去解析,處理器對解析結(jié)果進行處理。”

    “顯然關(guān)鍵在解析器,如果你是從頭做起,那么問題至少有四。”冒號扳著指頭數(shù):“第一、費時寫解析器代碼;第二、費時調(diào)試解析器代碼;第三、如果用戶更改格式標準,你得重復(fù)做上兩件事;第四、如果這段程序是大型程序的一部分,任何改動都可能意味著軟件的重新編譯、連接、測試、打包、部署等等。如果因為你的緣故公司不得不頻頻發(fā)布補丁包的話,你的飯碗恐怕是朝不保夕了。”

    還是句號機靈:“既然談到了元編程,一定是利用元編程,根據(jù)不同的格式標準自動生成相應(yīng)的解析器代碼。不過——此法雖一勞永逸,但難度似乎不小啊。”

    “思路對頭!”冒號贊許道,“大家聽說過LexYacc嗎?它們能根據(jù)格式標準生成相應(yīng)的解析器代碼。更妙的是,格式標準不限于靜態(tài)數(shù)據(jù),甚至可以含有動態(tài)指令!這意味著用戶不僅能定義業(yè)務(wù)數(shù)據(jù)格式,還能定義業(yè)務(wù)流程。”

    “這敢情好!”嘆號興奮地說。

    “如果知道LexYacc本來就是編寫編譯器和解釋器的工具,你就不會驚訝于它們的強大了。順帶說一句,編譯器本身就是元編程的典型范例——把高級語言轉(zhuǎn)化為匯編語言或機器語言的程序,不就是能寫程序的程序嗎?”冒號引申開來,“更進一步地,我們可以定義自己的領(lǐng)域特定語言DSL,更加靈活方便地處理客戶邏輯。”

    逗號有點糊涂了:“領(lǐng)域特定語言?就是前兩堂課提到的非通用編程語言吧?怎么和元編程也扯上關(guān)系了?”

    “不是扯上關(guān)系,而是它們之間本來就有著千絲萬縷的聯(lián)系。”冒號糾正著,“相比第三代的通用編程語言,領(lǐng)域特定語言由于其在應(yīng)用范圍上和語法上的限制而顯得簡單、針對性強,有時被成為‘小語言’(little language),也是一種特高級語言very high-level programming language ,簡稱VHLL),屬于第四代編程語言。”

    冒號說到此處,逗號猛地一拍腦門:“哦,我明白了。第四代語言最終需要編譯為機器語言,而編譯器就是元編程的應(yīng)用。”

    “你只說對了一半。”冒號不疾不緩地說,“DSL一般不會一步到位地編譯為第一代的機器語言或第二代的匯編語言,而是通過現(xiàn)成的編譯器生成器compiler-compilercompiler generator)首先轉(zhuǎn)化為第三代的高級語言。這樣不僅大大降低了難度,也方便了程序的調(diào)試。剛才提到的YaccYet Another Compiler Compiler)便是這樣的工具,能為解析器parser)產(chǎn)生C程序,多用于Unix下的編程。更現(xiàn)代的工具如ANTLR (ANother Tool for Language Recognition),能生成C、C++、Java、C#Python等多種語言的源程序。”

    引號立刻聯(lián)想到:“我記得框架Hiberate的必備庫中就含有antlr.jar文件,與這個ANTLR有關(guān)嗎?”

    “說得正是!”冒號很滿意學員完美的配合,“Hiberate中的HQLHibernate Query Language)是典型的DSL,需要通過ANTLR來解析。你們可以驗證一下,在HibernateAPI中有org.hibernate.hql.antlrpackage,但在其發(fā)布的源代碼中相應(yīng)的目錄下卻看不到一個Java源文件。卻是為何?蓋因此package中所有的源代碼都是在ant build中自動生成的,這些非人工編輯的文件是不會放在版本控制中的。”

    眾人茅塞頓開。

    句號想通了一個邏輯:“元編程作為超級范式的一個體現(xiàn)是,它能提升語言的級別。比如,有了編譯器的存在,匯編語言升級為第三代高級語言;同樣借助YaccANTLR之類的元編程工具,第三代語言可以升級為第四代的DSL語言。”

    冒號并未就此止步:“將這一模式發(fā)揮到極致,便是更加激進的語言導(dǎo)向式編程[1]Language-Oriented Programming,簡稱LOP)。這種編程范式的思路是:在建立一套DSL體系之后,直接用它們來編寫軟件,盡量不用通用語言。””

    嘆號莫明其妙:“想法近乎瘋狂??!放著好端端的通用語言不用,先造一套專用語言,這么做劃算嗎?”

     “如果一個大型系統(tǒng)涉及的領(lǐng)域十分專業(yè),包含的業(yè)務(wù)邏輯十分復(fù)雜,為其定制DSL或許會磨刀不誤砍柴工。我們通過下面的兩個圖比較一下這種范式與主流編程范式的不同之處。”冒號映出新的投影——

     “由于DSL比通用語言更簡單、更抽象、更專業(yè)、更接近自然語言和聲明式語言,開發(fā)效率顯著提高,因此圖中手工部分的時間相應(yīng)減少。此外尤為關(guān)鍵的是,這種方式填補了專業(yè)程序員與業(yè)務(wù)分析員之間的鴻溝。要求一個非專業(yè)編程的業(yè)務(wù)分析員用DSL來開發(fā)固是勉為其難,但要做到讀懂代碼并審查其中的業(yè)務(wù)邏輯則已非難事。” 冒號細解個中要點,“如果說OOP的關(guān)鍵在于構(gòu)造對象的概念,那么LOP的關(guān)鍵在于構(gòu)造語言的語法。有人認為LOP是繼OOP之后的下一個重要的編程范式,我們不妨拭目以待。”

    句號整理了一下頭緒:“能不能這么說:如果處理一些復(fù)雜、非標準格式的文檔,可以考慮用元編程;如果整個業(yè)務(wù)邏輯復(fù)雜多變,可以考慮利用現(xiàn)有的DSL或創(chuàng)造新的DSL來處理業(yè)務(wù),即所謂的語言導(dǎo)向式編程。”

    “總結(jié)得不錯,不過當特定格式的文檔有了專門的解析器后,這種文檔格式標準就可視為一種語言了,不是嗎?這本質(zhì)上就是DSL啊。”冒號出語點化。

    句號頓時醒悟:“是啊,就像XML、HTML一樣,能被程序認識的格式可不就是一種計算機語言嘛。”

    冒號將話題延伸:“我們的想象力可以再狂野些,在文本DSL的基礎(chǔ)上裹以圖形界面,從而引進圖形語言。如果再將部分業(yè)務(wù)邏輯開放給用戶定制,那么你的客戶會欣喜地發(fā)現(xiàn),他們的經(jīng)理只要點點鼠標就可以改變整個業(yè)務(wù)流程了,而這一切不僅不需要軟件開發(fā)方或第三方的參與,連本公司的技術(shù)人員也免了。這時候倒是你的老板發(fā)愁了:你的設(shè)計太過完美,客戶的后續(xù)開發(fā)費怕是賺不到啰。”

    眾人一樂。

    問號繼續(xù)發(fā)問:“還有其他元編程的應(yīng)用嗎?”

    冒號隨口舉了幾例:“元編程的例子比比皆是:許多IDEVisual Studio、DelphiEclipse等均能通過向?qū)?、拖放控件等方式自動生成源碼;UML建模工具將類圖轉(zhuǎn)換為代碼;Servlet引擎將JSP轉(zhuǎn)換為Java代碼;包括SpringHibernate、XDoclet在內(nèi)的許多框架和工具都能從配置文件、annotation/attribute等中產(chǎn)生代碼。”

    引號仍不知足:“這些應(yīng)用雖然典型,但都是些開發(fā)工具、框架引擎之類的基礎(chǔ)軟件,有沒有平時編程就能用到的例子?”

     “當然有!”冒號堅定地答復(fù),“有時程序中會出現(xiàn)大量的重復(fù)代碼,卻囿于語法上的限制無法進一步抽象化和模塊化。如果采用手工編寫或者單純拷貝的方法,既費時又易錯,顯為下策。有時可借助IDE內(nèi)置的代碼生成功能,但一方面局限性很大,另一方面無法自動化版本化。”

    問號插問:“什么叫版本化?”

    冒號解釋:“理想情況下,一個程序員對程序的貢獻都應(yīng)該保存在版本控制系統(tǒng)(version control system)中,以便跟蹤、比較、改進、借鑒和再生成。在IDE下自動生成的代碼本身可以被記錄,但產(chǎn)生代碼時的行為卻不能被記錄,幾次簡單的鼠標動作就能產(chǎn)生較大的代碼差別,使得版本比較的意義大打折扣。順便說一句,離開IDE就無法編寫、編譯或調(diào)試的程序員,如同卸盔下馬后便失去戰(zhàn)斗力的武士,是殘缺和孱弱的。”

    問號有些明白了:“這是因為鼠標行為本身在代碼中是沒有痕跡的。”

    “不僅是鼠標行為,有些需要鍵盤交互的行為也是沒有痕跡的。比如在命令行下用debugger來調(diào)試的行為無法被記錄,也難以重復(fù)和自動化,只能作為權(quán)宜之策。相比之下,日志(logging)和單元測試(unit test)具有明顯的優(yōu)勢[2]。”冒號答完,立馬重返主題,“回到上面的問題,既然有重復(fù)的代碼,不能從語法上提煉,不妨退一步從文字上提煉。我們可以利用AWK、Perl之類的擅長文字處理的腳本語言,當然也可以用JavaC等非腳本語言,再輔以XSLT之類的模板語言,自動生成重復(fù)代碼。這樣不僅靈活性強,而且生成代碼的代碼——也就是元程序代碼可以被重用,元程序的數(shù)據(jù)來源也能版本化。”

    句號深得要領(lǐng):“就像Hibernate中的antlr包一樣,真正的源碼反而不在版本控制中了。一方面沒有保存的必要——可以自動生成;另一方面沒有比較的必要——元程序的數(shù)據(jù)來源的變化比實際源碼的變化更簡明、更直觀。”

    冒號繼續(xù)推進:“另外,有時程序的結(jié)構(gòu)需要動態(tài)改變,而Java、C++靜態(tài)語言是不允許動態(tài)變更類的成員或?qū)崿F(xiàn)代碼的,利用元編程便可突破這種限制。”

    逗號恍然大悟:“原來元編程就是編寫能自動生成源代碼的程序。”

    “也不盡然。”冒號馬上修正道,“自動生成源代碼的編程也屬于另一種編程范式——產(chǎn)生式編程Generative Programming[3]的范疇。區(qū)別在于后者更看重代碼的生成,而元編程看重的是生成代碼的可執(zhí)行性。另外,除了在編譯期間生成源代碼的靜態(tài)元編程,還有能在運行期間修改程序的動態(tài)元編程。從低級的匯編語言到一些高級的動態(tài)語言如Perl、PythonRubyJavaScriptLisp、Prolog等均支持此類功能。比如許多腳本語言都提供eval函數(shù),可以在運行時將字符串作為表達式來運算[4]。”

    問號突然問道:“編寫病毒算不算元編程?”

    “編寫一個只是刪除或感染文件的病毒,不必用到元編程。但如果要開發(fā)一個能自我變異的智能病毒,那就需要元編程了。不過你要是把元編程用在這方面,可別說是我教的。”冒號開了個玩笑。

    引號自言自語:“程序的程序,就是程序的平方。”

    “也可以是程序的立方,四次方……理論上是無限次方。在傳統(tǒng)的編程中,運算是動態(tài)的,但程序本身是靜態(tài)的;在元編程中,二者都是動態(tài)的。元程序?qū)⒊绦蜃鳛閿?shù)據(jù)來對待,能自我發(fā)現(xiàn)、自我賦權(quán)和自我升級,有著其他程序所不具備的自覺性、自適應(yīng)性智能性,可以說是一種最高級的程序。它要求編程者超越常規(guī)的編程思維,在一種嶄新的高度上理解編程。想象一下,”冒號激情勃發(fā),“如果有一天機器人能自我學習、自我完善,甚至能生產(chǎn)新的機器人,實現(xiàn)‘智能繁衍’,是不是很美妙?”

    “我怎么覺得特恐怖呢?豈止是程序員,所有地球人的飯碗都會被它們砸光了。”嘆號此言一出,眾皆忍俊不禁。

     
    ,插語

    [1] Martin Ward最早提出此范式,見參考文獻【1】。

    [2] 雖然調(diào)試與測試和日志不是一碼事,但合理的日志和單元測試能大量減少調(diào)試工作。

    [3] 也譯作“生成式編程”,屬于自動編程(Automatic Programming)范疇。

    [4] 考慮到eval過于廣泛和強大,有些動態(tài)語言還提供其他更明確和更安全的元編程機制,如JavaScript可用字符串來構(gòu)建Function,Ruby更是提供了define_method、instance_eval、 class_evalmodule_eval等諸多元編程方法。


    總結(jié)

    • 元編程是編寫、操縱程序的程序。在傳統(tǒng)的編程中,運算是動態(tài)的,但程序本身是靜態(tài)的;在元編程中,二者都是動態(tài)的。
    • 元編程能減少手工編程,突破原語言的語法限制,提升語言的抽象級別與靈活性,從而提高程序員的生產(chǎn)效率。
    • 元編程有諸多應(yīng)用:許多開發(fā)工具、框架引擎之類的基礎(chǔ)軟件都有自動生成源代碼的功能;創(chuàng)造DSL以便更高效地處理專門領(lǐng)域的業(yè)務(wù);自動生成重復(fù)代碼;動態(tài)改變程序的語句、函數(shù)、類等等。
    • IDE下自動生成的代碼通常局限性大且可讀性差,小操作可能造成的源碼上的大差異,削弱了版本控制的意義。用自編的無需人機交互的元程序來生成代碼,只需將元程序的數(shù)據(jù)來源版本化,簡明而直觀。同時由于元程序可以隨時修改,因此局限性小,更加靈活。
    • 語言導(dǎo)向式編程(LOP)通過創(chuàng)建一套專用語言DSL來編寫程序。相比通用語言,DSL更簡單、更抽象、更專業(yè)、更接近自然語言和聲明式語言、開發(fā)效率更高,同時有助于專業(yè)程序員與業(yè)務(wù)分析員之間的合作。
    • 語言導(dǎo)向式編程一般通過元編程將專用語言轉(zhuǎn)化為通用語言。
    • 產(chǎn)生式編程與靜態(tài)元編程都能自動生成源代碼。產(chǎn)生式編程強調(diào)代碼的生成,元編程強調(diào)生成代碼的可執(zhí)行性。此外,動態(tài)元編程并不生成源代碼,但能在運行期間修改程序。
    • 元程序?qū)⒊绦蜃鳛閿?shù)據(jù)來對待,有著其他程序所不具備的自覺性、自適應(yīng)性和智能性,可以說是一種最高級的程序。

     

    “”參考

    [1] Martin WardLanguage Oriented Programminghttp://www.cse.dmu.ac.uk/~mward/martin/papers/middle-out-t.pdf

    [2] Sergey DmitrievLanguage Oriented Programming: The Next Programming Paradigm

    http://www.onboard.jetbrains.com/is1/articles/04/10/lop/mps.pdf

    [3] WikipediaMetaprogramminghttp://en.wikipedia.org/wiki/Metaprogramming

     

    posted on 2008-11-10 23:40 鄭暉 閱讀(2340) 評論(0)  編輯  收藏 所屬分類: 冒號課堂

    導(dǎo)航

    統(tǒng)計

    公告

    博客搬家:http://blog.zhenghui.org
    《冒號課堂》一書于2009年10月上市,詳情請見
    冒號課堂

    留言簿(17)

    隨筆分類(61)

    隨筆檔案(61)

    文章分類(1)

    文章檔案(1)

    最新隨筆

    積分與排名

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 免费A级毛片在线播放| 99视频全部免费精品全部四虎| 欧美a级在线现免费观看| 亚洲男人都懂得羞羞网站| 国产免费久久久久久无码| 国产精品久久香蕉免费播放| 亚洲欧洲日本在线观看 | 亚洲乱亚洲乱妇无码麻豆| 免费看黄网站在线看| 国产一级淫片a视频免费观看| 亚洲AV无码一区二区三区网址| 成人黄页网站免费观看大全| 亚洲中文字幕久久久一区| 日韩在线免费电影| 国产精品亚洲片在线观看不卡| a级片免费观看视频| 亚洲欧洲在线观看| 91黑丝国产线观看免费| 91在线亚洲综合在线| 国产hs免费高清在线观看| 牛牛在线精品观看免费正 | 亚洲av无码成人影院一区| 免费中文字幕在线| 三年在线观看免费观看完整版中文 | 国产亚洲女在线线精品| 免费在线观看黄色毛片| 在线观看免费视频一区| 亚洲黄色免费在线观看| 成年人免费观看视频网站| 午夜在线免费视频 | 亚洲免费无码在线| 久操视频在线免费观看| 亚洲xxxxxx| 亚洲国产精品一区二区九九| 免费福利电影在线观看| 亚洲综合色区中文字幕| 亚洲国产成人久久一区久久| 十九岁在线观看免费完整版电影| 四虎必出精品亚洲高清| 国产AV无码专区亚洲AV手机麻豆| 亚洲无码一区二区三区|