程序員的語言“艷遇史”(七)——電臺播音員Scheme

作者: fzwudc  來源: 博客園  發布時間: 2010-07-30 16:20  閱讀: 1598 次  推薦: 0   原文鏈接   [收藏]  

  程序員的語言“艷遇史”(一)——班長pascal

  程序員的語言“艷遇史”(二)——計算中心管理員小C

  程序員的語言“艷遇史”(三)——法國外教prolog

  程序員的語言“艷遇史”(四)——數學系師姐Forth

  程序員的語言“艷遇史”(五)——辦公室秘書Smalltalk

  程序員的語言“艷遇史”(六)——網絡工程師Perl

第七個女孩  電臺播音員scheme

  (***以下小說情節純屬虛構,供朋友們在緊張編程后輕松一下,如有雷同純屬巧合,切勿對號入座***)

  一、天籟之音

  早班車上,每過一站,都是一陣洶涌的人流波動。我好不容易搶到一個座位,環顧四周,沒什么老人孕婦,竊喜。最近一周倒霉,每次才占到空位,都迫于群眾壓力,當了雷鋒,連假裝看窗外都不成。我放心的坐下,隨手抹了一把汗。其實我本可以坐11路車上班,路程還少兩站,也沒這么擠。可是那路車整天播新聞廣播,主持人聲音和破鑼似的,哪能和音樂交通廣播scheme姐姐的天籟之音比啊。

  不錯,7:30節目準點開始,車上伴聽傳來那個我熟悉的女聲,“聽友marry通過本節目給她的男朋友點歌一首,她在發來的短信里說,漫漫人生路,有你長相伴……要點歌的朋友可以發短信到……”。我急忙掏出手機發短信,不用主持人說,那個SP特服號我太熟了。為什么呢,本公司正是音樂交通廣播唯一指定短信合作伙伴,節目流程還是我設計的。呵呵,就算當公司產品的義務測試員了。就是短信信息費太貴,靠,一條5元,跟搶劫沒什么兩樣。改天找我們麥總報銷。

  二、 麥總是誰?

  麥總就是我大學那個老同學麥東啊。我就是受到他的邀請,才到現在這家公司的。大學畢業時,麥東一點都不為工作著急。我當時還百思不得其解,現在我才明白,還找什么工作啊,人家是為社會創造就業機會的層次。麥東老爸是副市長,有這個政商背景在,還有什么搞不定的。

  麥東畢業后,玩了幾年,被他爸罵得夠嗆。于是就借錢搞了一個從事電信增值業務的公司。公司初創缺人,他就想到我這個大學“同居”多年的死黨,叫我助他一臂之力。我正好做網絡集成這個行業做累了,和領導關系也不好,想換換口味,就離家到了這個陌生的城市。

  到公司一看,麥東這家伙,還和當年一樣色。才聊幾句,就和我對外面女秘書的身材進行一番研討。終于談到工作,他決定委以我公司技術總監一職,命我即刻上任。我開始還假意推辭,到技術部一看,就一個維護機器的小弟,一看名片,還是技術部副總。四周再逛了一下,公司就十來個人,稱呼都是某總,連做衛生阿姨都是保潔部主管。我大怒,整一個皮包公司嘛,準備不干了。麥總急忙挽留,說就當到這里旅游,也得呆三個月,否則老同學情意就沒了。

  后來我才知道,對短信SP這個行業來說,技術不是主要因素,關鍵還是有沒有信息源,和運營商關系鐵不鐵。我們麥總年輕有為,什么中高考查分、電臺電視臺節目互動,紛紛搶到手里。以前民國時候,形容軍閥有一句話“大炮一響,黃金萬兩”,我們公司的炮彈就是短信群發。那時每上一個新節目,我最喜歡的事情就是趴在服務器終端前,邊看用戶短信流量邊流口水。一條、二條……一萬條,那就是錢啊。我和麥東經常取笑那些在.COM公司的兄弟,它們有盈利模式嗎?看看我們,已經搞定。現在我再也不嫌人少了,麥總催了我幾次,叫我搞搞招聘。我都給他頂回去,說忙得過來。招人,我傻呀,人少才好分錢啊。唉,當時真是小農意識濃郁。

  三、和SICP的相遇

  一天,我閑得無聊,就去逛新華書城。忽然耳邊傳來了那個熟悉的女聲,“現在我為大家獻歌一曲,高天上流云……”。這不是音樂交通廣播的scheme嗎,她怎么也來書城了。我和沒頭蒼蠅一樣,在書城里四處亂竄。后來才搞清楚情況,原來書城五樓正在搞音樂交通廣播聽友見面會。等我趕到,已經曲終人散。唉,錯過了和scheme姐姐見面的機會。

  我正郁悶著,隨手抓起一本別人不要的丟在書架上的書。哈哈,沒想到情場失意,淘書竟然淘出一個寶貝。那就是大名鼎鼎的SICP,北大裘宗燕老師的譯本《計算機程序的構造和解釋》。以前一直聽說過Lisp這門古老的語言,可是總不得其門而入,今日終于得償所愿。

  該書使用的程序設計語言是上個世紀70年代誕生在MIT人工智能實驗室的Lisp方言,名為Scheme。它的發明者是Guy L.Steele和他的老師Gerald Jay Sussman。Scheme語言秉承了Lisp傳統,采取了基于表達式計值和函數施用的計算模型,而且無論程序還是數據都具有一致的S表達式語法。

  雖然Lisp方言很多,但Scheme絕對是有特殊歷史地位的一個。Scheme比其他早期lisp方言具有更堅實的理論基礎,也可以說更“純”,它的許多概念奠基于數學里的無類型Lambda演算。雖然Lisp也是來源于此,但它的許多方言并不嚴格遵循該理論。Scheme語言把詞法作用域引入了Lisp家族,而其他的Lisp方言除了后來的Common Lisp外,大都采用動態作用域。Scheme語言還鼓勵大家大膽的使用遞歸,而不用擔心堆棧溢出,因為它把尾遞歸優化作為實現標準。

  SICP這本書(Sussman還是作者之一),實際上就是他們Scheme語言設計和研究的一個縮影。書的難度確實不低,我當時了解到這竟然是MIT入門課程6.001的教材,簡直震驚了。難道中美計算機科學教育的差距有這么大嗎?后來我在“Joe on Software”里看到Joe對這本書及相關課程的說法:(譯文摘自《More Joe on Software》中文版《軟件隨想錄》中的“Java語言學校的危險性”)

   “我讀的這門導論課,是賓夕法尼亞大學的CSE 121課程,真是讀得苦不堪言。我注意到很多學生,也許是大部分的學生,都無法完成這門課。課程的內容實在太難了。我給教授寫了一封長長的聲淚俱下的Email,控訴這門課不是給人學的。賓夕法尼亞大學里一定有人聽到了我的呼聲(或者聽到了其他抱怨者的呼聲),因為如今這門課講授的計算機語言是Java。”

  看到這里,心里平衡了不少,因為我清楚的記得我在大學一二年級的水平。不過SICP這本書對Scheme語言的介紹只能算是中級,它的重點是編程思想和計算模型,而非語言本身。從語言角度講,它至少忽略了兩個重要主題:宏Macro和延續Continuation。從理論角度講,它并沒有多講Lambda演算方面的內容。如果把這本書當做入口,再深度鉆研下去,你就會發現一個更宏大的領域——函數程序設計FP。

  四、仰望FP星空

  函數程序設計作為一場運動,已經統治歐美程序設計語言理論界多年。如果把FP當做一個武林門派,那開山鼻祖就是邏輯學家Alonzo Church。他在1941年發明Lambda演算,這是一個研究可計算函數及函數施用的形式系統。上個世紀50年代,John McCarthy和他的小組發明了Lisp語言,把Lambda演算引入了計算機世界。到了70~80年代,FP終于成為顯學。連命令式語言的老祖宗Fortran創始人JohnBackus都倒戈了,他在1977年發表了著名的圖靈獎演講“Can Programming Be Liberated From the von Neumann Style?”, 大力鼓吹FP。FP分支眾多,目前比較流行的程序設計語言有Lisp/Scheme、ML、Haskell、Erlang等。最近連微軟這樣一向保守的工業主流企業,也借鑒ML語言出了F#這樣的東西,這在以前想都不敢想。

  那時我也是附庸風雅,根本不是學術界的一份子,竟然叛變革命,也開始看函數程序設計方面的文獻。我下載了Steele和Sussman為Scheme語言發表的一系列論文,這些文章完整討論了Scheme的語言設計、解釋器實現、編譯器實現,甚至一個Scheme硬件處理器的實現,堪稱計算機科學技術的學術典范,名噪一時。每篇論文都以Lambda作為題目開頭,比如“Lambda: The Ultimate Imperative”、“ Lambda: The Ultimate Declarative”等等。此風一起,后有好事者加以模仿,在寫Scheme語言或其他函數語言編譯技術有關的論文時,也常用Lambda開頭。國外一個討論程序設計語言的學術網站,起名叫Lambda the Ultimate,看來也是受此影響。

  一個晚上,我讀論文讀累了,走到房間陽臺透一透氣。小區里的空氣是悶熱而污濁的,空調外機響著,樓下幾個大排檔人頭聳動,吵得要死。我如同一個文藝青年,抬頭仰望星空,回想函數程序設計60多年的歷史,心潮澎湃,頗有眾人皆醉唯我獨醒之態。忽然接到麥東電話,叫我一起到某新開酒吧happy。這幫俗人!我堅決予以拒絕,決定今夜青燈古佛,陪論文度過。麥東使勁誘惑,“來吧,我還請了音樂交通廣播的幾個美女,嘿嘿!”。什么,音樂交通廣播,美女!我腦中立刻想到了scheme姐姐,立馬把論文丟在一邊,直奔酒吧而去。到了才發現此美女非彼美女,是電臺廣告部的幾個人,又被騙了!

  五、何為情商

  麥東這個人,學習一般,對學術問題更沒什么興趣。他學生時代就是我們班一活寶,專業追女,業余學習。畢業論文更是一塌糊涂,后來兄弟幫他捉刀一篇,幾乎逐子逐句改過,才過了關。也許就是這份交情,他后來開公司才想到我。但是和他相處一段,我不能不佩服他的情商。所以人家是老板,我們是打工仔。

  就拿和運營商公關一事講吧。聯通最近部門調整,新成立了增值業務部,我們去拜訪對方新領導。車到聯通大樓門口,麥東鬼鬼祟祟的換了一部手機,名片也換了一個版本。我極為不解,干嘛?麥東白了我一眼,說“你真木。到聯通公司,你總不能拿著一部中國移動的手機吧。這讓別人不爽。”。我們公司和三個主流運營商移動、聯通、電信小靈通,都有SP接口。麥東給業務部同事和他自己準備了三套手機、三種名片,看人擺碗碟,真夠絕的。

  出去商務談判,坐在麥東旁邊,差點把我嚇出心臟病。整一個賣拐的大忽悠,上到音信互動節目,下到網絡布線工程,沒有不能做的。我看要是對方講開發航空母艦,估計他眉頭都不眨,也能應承下來。有幾次我在桌下,直踢他腳,他還滔滔不絕,口若懸河,弄得我狂汗。后來麥東和我講,這就叫氣勢,商場中沒這個自信,人家看不起的。我反問,要是公司沒能力開發怎么辦?麥東說轉包啊,能拿到單子才是爺啊,后面做工程的和乞丐一樣一大溜。我啞口無言。

  每年315消費者權益日,我們都特緊張。就怕某個用戶亂投訴,媒體來個曝光,公司就慘了。那時我們還是很守規范的,騙都是騙,但是用戶訂購的上行短信都還是有記錄的。但是有的用戶對資費和服務就是不認可,運營商分錢沒問題,投訴全往我們頭上推。我們技術部還認死理,和用戶比對短信記錄,差點沒吵起來。麥東多次力挽狂瀾,花錢消災,把用戶伺候得服服帖帖走人。這就是功夫啊。他還發動關系網,建立投訴預警系統,各大媒體、消協加工商局,四處打點,防范于未然。

  有這樣的老總在,下面工作好做多了,我這個技術總監也日漸輕松。SP短信技術系統還是比較簡單的,我借鑒SICP書中介紹的解釋器手法,偷空開發了一個簡單的DSL,這些就可以不用C語言做流程了,以后上新節目讓小弟編個DSL腳本就行了。溫飽思淫逸,我有時上班空下來,不務正業,也研究研究Scheme語言。

  六、從理論到機器的旅程

  函數程序語言研究群體畢竟是計算機科學家,不是搞純數學。您鼓吹了半天,總得有個在機器上可運行的東西出來吧。所以我們的理論家也不得不臟一下手,考慮一下編譯問題。他們的套路和傳統命令式語言的編譯技術是極為不同的。很多函數語言編譯器開發者經常分兩個層次考慮問題:

  1、如何把各種各樣的語言構造,統一歸結為函數計算模型,即轉換為lambda演算形式;

  2、如何把lambda演算形式及其歸約操作,在主流von Neumann機器這個異構的設施上有效予以實現。

  在這些問題上,無盡的努力已經耗去了,多少人白了少年頭。下面我們看看,在經典的Scheme語言實現中,是如何處理這兩個問題的。

  Lisp傳統中,由于數據和程序表示的一致性,程序的轉換可以通過數據結構的操作來實現。由于可以用read原語像輸入數據一樣輸入S表達式,不用再進行語法解析,在Lisp中編寫解釋器或編譯器是一件很容易的事情。Lisp中經常用于程序轉換的手段稱之為特殊型。首先可以實現很小一個子集的特殊型,然后利用這個子集再去定義新的特殊型。在解釋器或編譯器的處理中,在此子集合外的特殊型被翻譯成預先定義的特殊型,然后再對變換后的表達式進行操作。新定義的特殊型稱之為宏,翻譯過程稱之為宏展開。

  所以對于第一個問題,Scheme的回答就是把lambda演算形式作為核心子集,而其他的程序構造定義為語言的宏。

  看兩個簡單的Scheme語言程序。

  程序一:引入局部詞法環境的let表達式

  (let
   ((a 1) (b 2))
  (+ a b))

  它被宏展開后,可以轉換為類似這樣的一種形式:

  ((lambda(a b) (+ a b))
   1 2)

  可以看到,變成了一個lambda表達式對常數1和2的施用操作,結果是3。

  程序二:引入副作用的begin表達式和set!表達式

  (definea 0)
  (define b 0)
  (begin
     (set! a 1)
     (set! b 2)
     (+ a b))

   其中的begin表達式被宏展開后,可以轉換為如下一種形式:

  ((lambda(x)
      ((lambda (y)
        ((lambda (z) z)
           (+ (getbox a) (getboxb))))
      (setbox! b 2)))
   (setbox! a 1))

  變成了三個lambda表達式的連續的施用操作。可以看到x和y變量實際上是沒用的,(setbox! a 1)和(setbox! b 2)兩個表達式的返回值被拋棄了,只有最后一個(+ (getbox a) (getbox b))的值作為整個表達式的返回值。所以,如果begin表達式中的子表達式沒有副作用,那對整個程序的計算是沒有意義的。

  還要注意的是對set!賦值表達式的轉換。如果不對set!表達式進行處理,變量值允許變化,就無法保持lambda演算理論的純潔性,也無法對程序進行數學語義推理了。

  這里變的戲法是為被賦值的變量引入一個間接層,把對變量的賦值和引用轉換為對內存數據結構的讀寫原語getbox和setbox!。變量指向該內存數據結構,在程序運行時間內不再改變,這樣在形式上就符合lambda演算中變量一經綁定不再改變的特性了。

  同樣,Scheme語言中其他特殊型比如什么let*、letrec、and、or、cond、case、do、define,它們可以被宏轉換成quote,setbox!,getbox,if和lambda這些核心lambda演算的形式。

  下面解決第二個問題,lambda演算這種可計算函數的模型如何能在狀態轉換的底層機器上跑起來。

  現在忘掉計算機,回到初中時代,怎么算三角形面積?底*高/2,表示成代數式:

  a * b / 2

  代入實際數值就可以計算了,有的人先算a*b,然后再除2;有的人先算b/2,然后再乘上a。都可以。如果讓計算機這個電子傻瓜幫你算,用貼近機器的匯編語言,你就得明確計算順序。我們用CPS(Continuation passing style)形式的Scheme代碼來顯式的表達計算順序。

  一種是( * a b (lambda (x) (/ x 2 (lambda (z) z))))。

  另一種是( / b 2 (lambda (x) (* x a (lambda (z) z))))。

  注意*和/的操作類型不再是 number number -> number,而變成了number number continuation -> number 。多了一個continuation延續參數,*和/的結果不是立即返回,而是作為參數傳給continuation,使得計算繼續持續下去。現在這個式子,不僅是一個和原來的代數式語義相同的代數式,而且可以被看成凸顯控制流的中間代碼。

  我們就第二個式子繼續變換:
  j = (/ b 2 (g a))
  g = (lambda (y) (lambda (x) (* x y f)))
  f = (lambda (z) z)

  這里生成了三個新表達式,注意原來的兩個continuation不再是匿名函數了,而被提升到全局環境,分別用f和g引用。注意這里的函數g,它對應于原來的(lambda (x)(* x a (lambda (z) z))),多了一個參數y,代替式子里的自由變量a。

  假設有一個堆棧機作為目標機器,其中push是入棧指令,div和mul分別是除法和乘法指令,goto是跳轉指令。我們就可以把上面的中間形式轉換為匯編偽代碼:

  j:              // 匯編語言標號
    dd a …          // 這里定義了兩個變量
    dd b …
    push b
    push 2
    div
    push a
    goto g
  g:
    mul
    goto f
  f:

   注意這里所有對延續的函數調用都屬于尾調用tail call,在編譯處理上都不生成保存函數返回地址的代碼,直接goto到一個標號地址即可。可以看到,代碼還可以再簡化,很多編譯器生成的指令是不必要的。這就是兩個不同計算模型轉換的代價,我們這個例子太小,還不怎么能說明問題。

  以上我們殺雞用牛刀,展現了經典Scheme語言編譯器如何把一個弱智的lambda表達式轉換為機器代碼的過程,演示了每步的程序形式。在其中的第一步和第二步分別使用CPS變換和Lambda Lift變換,最終生成了虛擬堆棧機的代碼。這些程序變換是否語義上與原來一致呢,這是一個關于可信編譯器的證明問題了,太麻煩了,還是留給那些計算機科學家吧。

  七、離別的日子

  真是世事無常,我們的好日子才幾年,就結束了。麥東他爸因為房地產土地買賣的問題被雙規了。在此打擊下,麥東失魂落魄,也不怎么來公司了。業務雖然還正常運轉,但已不比從前。中高考查分信源丟了,今年移動的SP新節目報批也遲遲沒有下來。整個行業背景也在變化了,移動夢網的新政即將出臺,將來的監管力度會更嚴。苦撐著沒多久,麥東和我做了一次長談,決定把公司賣了,出國算了。我當然支持他了,都是兄弟嘛。我決定渡過交接期后,也辭職回家。

  在即將離開這個城市的時候,我有一樁未了的心愿。大家都猜到了,那就是無論如何要見scheme姐姐一面。三年了,天天在公車上聽到她的聲音,她就好比我身邊的一個朋友。我決定不再錯過,通過電臺活動部的小張,我混進了廣電大樓。

  站在播音室門口,我坎坷不安,手汗都把日記本弄濕了。突然門開了,一個身材臃腫的中年婦女出現在我的面前,穿著一件普通的黑裙子,頭上戴著我媽那個年代的發夾。

  “你好,我是scheme。”

  后面的幾分鐘我恍惚夢游,帶著scheme簽名的日記本,我走出了廣電大樓。看見了滿天星光,我不禁啞然失笑。從旁邊的商鋪里傳來那熟悉的歌聲:

  “千萬里,我追尋著你,

  可是你卻并不在意,

   ……”

0
0
 
標簽:Scheme
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()