小松鼠嚇了一跳,有了魔法眼鏡後,這世界看起來完全不一樣了

2008年8月9日 星期六

不愉快的基因

這部由竹內結子和內野聖陽主演的日劇,開頭讓人有點摸不著頭緒,不知道該放進那一組日劇類型裡。某方面來看,帶有圈套、時效警察、偵探伽利略那種無厘頭的風格。內野聖陽的教授角色有點類似圈套和伽利略裡面的教授類型,特別是類似圈套裡面那種自大。小林聰美的角色很像從時效警察裡面跳出來的(小田切讓也有演,但在前幾集是個神秘人物)。另外一方面,又有點像是螢之光那種類型的曖昧三角習題,教授有點像是課長的角色,看著竹內結子則和黃川田將也這對年輕人談戀愛。

一開始車內片頭、外加回憶的感覺,則讓我聯想到竹內結子和田村正和演的新紐約戀愛物語。但片中穿插的昆蟲動畫,卻似乎完全否定了這個想法。

實際上,比較起來,不愉快的基因的風格比較像是新紐約戀愛物語。一樣是多年的愛恨糾纏與無奈。

竹內結子飾演的是一名生物研究者,故事開始時是個研究生。高學歷、從事實驗研究的人,與一般所謂的正常的社會人士,在生活經驗和價值觀上有很多斷層。很多研究者的生命是奉獻給工作的,生活與研究沒有明顯的分隔,沒有所謂的上下班之分。當然,這個只是程度上的問題。有些特殊行業也有類似的情形,像是明星,平常走在路上也是明星,沒有什麼上下班的分別。另外就是社會價值觀很不同。很多醫生也類似,因為常常要值班,生活和工作常常混在一起。

總之,就是很不一樣。問題來了,學者和社會還是要接觸的,兩個不相容的東西,碰在一起,會發生什麼事情呢?

這部日劇的重心就在這裡。裡面用兩個事件來展現這個主題,一個是竹內結子的感情生活。藉由和正常的小學老師交往,凸顯女性研究者的無奈。做實驗需要長時間待命,隨時應付突發狀況。而且,整個心思二十四小時都放在研究上,即使竹內結子和黃川田將也兩情相悅,但彼此的交往卻總是格格不入。劇中藉由黃川田將也的口中說出「為什麼我不能和一個正常一點的人交往」這種無奈。

另外一個事件,就是學者接受委託研究,以及籌募經費的問題。劇中的的學者接受委做研究。原本研究是單純找出事情的答案,是公正而單純的。但接受委託研究時,雇主往往希望的是你替他的答案找理由。學者的浪漫與現實社會的功利,產生了衝突。內野聖陽在劇中對竹內結子說,學者碰到社會總要吃虧的。

本劇前半後半中間的轉折看似突兀,其實是為了塞進這兩個主題。

但不管是研究也好、感情也好,都是生活。時間累積下來,也沒有什麼對不對,快樂也好,難過也好,這樣過了。大結局明顯的要反應這一點。

結局時,感情算是累積起來了,足以在結尾時爆發。但總覺得花了那麼多篇幅,可能還可以弄得更好、更細膩一點。

2008年8月2日 星期六

Last Friends (續2)

上野樹里飾演的岸本瑠可是劇中另一個重要角色。她的心理問題是性別認同問題。宗佑的病是理智與暴力慾望之間的矛盾,理智上他了解不該、不能用暴力解決問題,但卻無法克制這個衝動。而瑠可則是生理女性,但是心理上卻自認為是男性,因而產生衝突。除此之外,都屬於正常人。

另一個要角小武也類似。小武由於幼年時的陰影,恐懼與女性肉體接觸。如果他的性向是喜歡男性,那他就是一個正常的同性戀。但偏偏他除了那個恐懼外,是標準的異性戀。他因為不願提及年幼的陰影以及恐懼女性肉體接觸這件事情,所以需要解釋的時候,常偽裝成同性戀。

相較起來,美知留的問題要小些。她沒有那麼根本性的衝突。她一開始是打算一心一意的救贖宗佑。雖然她也許原本沒料到要付出這麼大的代價,但她其實幾乎是不惜犧牲她的一切來拯救宗佑的。這當然是浪漫的設定,但劇中表現的是除了瑠可外,她可以做所有讓步。可能很痛苦,但她可以讓步。

而宗佑說得沒錯,Share House 的人改變她了。接觸舊友瑠可及 Share House 的其他人之後,因為瑠可對美知留的重要性,足以和宗佑相比,美知留聽從朋友建議,多為自己想了一點,也同時開始多關心了這些新朋友。這時,救贖宗佑的願望,就和保有 Share House 的幸福產生了衝突。不過這個衝突本身也許體現了人性內在的一些衝突,但相較之下,沒有那麼異常。

Share House 航空公司二人組也有各自問題,也有著內心慾望、客觀環境之間的不協調。但相比之下,他們代表著「正常人」的矛盾與心理衝突。本質上其實類似,只因是大多數人都有的困擾,受到的心理壓力比較小。

劇情安排小武的不排斥與男人心的瑠可肢體接觸,而男人心的瑠可則喜歡美知留。而最後結局的另類家庭收場,象徵著協調。瑠可、小武、甚至美知留,都還保有原來的心病與衝突,但藉由「非正常」的家庭組織,這些衝突得到協調,因此能幸福的生活下去。非正常的組織結構,最大的困擾是外在的異樣眼光。但從內在來看,和正常家庭追求協調的目標與目的是一致的。唯一的問題只不過是,由於非正常的東西由於數量少,結構穩定性還有帶時間檢驗。但話又說回來,所謂的正常家庭組織,在現在環境變化那麼快,真的還有這個優勢嗎?離婚率不是高得可怕嗎?一般所謂正常與否,還是取決於旁人的異樣眼光吧。

別人跟你活的方式不一樣、喜好目標不同,所以呢?一個正常的人,有過異於常人的生活經驗後,他成為一個有特別的人?還是一個生病的正常人?

和充氣娃娃之戀不同理念的結局。

2008年7月31日 星期四

Last Friends (續)

所以宗佑其實夠聰明,聰明到可以了解自己心理上有問題,但是沒有聰明到能夠解決問題。他其實也知道用暴力無法解決他與美知留之間的問題,也懷疑他其他激烈手段能夠達到的效益,所以不斷的加碼或調整。不過面對美知留時,他沒有辦法克制暴力的衝動和控制慾,因為暴力這是他唯一能暫時解決問題的管道。所以理智面與野獸面產生了衝突,他清楚自己的目的是什麼,但看到美知留痛苦的答應和他在一起時,他徹底絕望了。因為他達到他的目的,美知留回來跟他在一起了。但是他也沒有達到他的目的,因為美知留很不快樂。

他其實本來多少意識到這一點。但直到這個時候他才面對這個事實。看著美知留在 share house時,快樂的情形,對照美知留和他在一起時的痛苦。之前還對於自己處理問題的「方式」抱持些許希望,現在徹底絕望了。理智上來說,放美知留走就可以了,但他也清楚知道自己沒辦法克制自己的控制慾,還是會繼續暴力。所以,他唯一能想到克制自己的方式,就是讓自己的心跳停止。

這有點像是「充氣娃娃之戀」的感覺一樣,宗佑是一個心理變態,但他和正常人真的有差那麼多嗎?如果內心深處像宗佑一樣,藏著這樣的猛獸,正常人會怎麼處理呢?能夠奮鬥到成為公務員,能夠在冷靜時結束自己生命,已算是很善良了。他在笨一點的話,其實可以選擇繼續加碼傷害,自己得不到的,也不要讓別人得到。

當然這是日劇用比較浪漫的觀點來說這個故事。

一般的觀點也許就是說宗佑這種人不值得同情。不過也得要有能力去同情、同理他,才談得上要不要、值不值得同情這回事。其實就像是獅子,天生有吃肉的慾望。所以他會抓可憐的兔子來吃。但是從大自然的角度來看,也沒有什麼對不對的,因為獅子天生就是這樣。如果這個獅子被灌輸了人類的價值觀,覺得自己很血腥殘忍。那麼,他的理智與慾望產生了矛盾,就像宗佑那樣,那他就生病了。獅子除了自殺外,沒有其他的方法克制自己吃肉的慾望。(除非是用更浪漫的方式,比方悠遊白書裡苦行的方式克制自己,或者吸血鬼用血清替代品這種幻想的產物。)

說野蠻殘忍,人類還更可怕。人類殺害動植物的理由,還不如獅子那樣不得已。話雖如此,但如果身為兔子,看到獅子,也還是要跑。要跑這件事情,無關於是否認同獅子。不需要因為害怕自己認同獅子,而不敢去理解獅子的心態。了解獅子的心態,反而更能幫助兔子逃脫。

美知留的情形又是另外一回事。過去我看到這種案例,覺得原因除了笨外,可能是因為受害者極端需要愛及重視,而施暴者能提供受害者這樣的感受。但看了 Last Friends 之後,有另外一個想法。美知留沒有那麼笨。她很清楚宗佑的暴力是很難改的,從第一次被毆打後,就知道了。她難以離開宗佑的原因是,她很同情宗佑,進而很可憐他。有點像是小白兔逃離獅子魔爪後,卻很擔心獅子餓肚子那種感覺。

美知留因為自己的成長背景類似宗佑,所以了解宗佑害怕寂寞的心情。她和宗佑一樣,也想要讓別人不再和自己過去一樣可憐。當然,小白兔因為同情獅子,而讓獅子吃掉,你可以說她笨,從另外一個角度來看,也可以說是很高貴。美知留不是完全沒有抵抗或逃跑能力,她是放棄抵抗。因為她對於宗佑的不安與寂寞感,能夠感同身受。所以她逃走後,一直對宗佑感到抱歉。從外人的角度來看,她有絕對正當的理由分手。但從她的角度來看,她一個人變得更幸福,留下宗佑一個人更加孤單,她覺得這樣對不起宗佑。在她眼裡,宗佑與其說是一個施暴者,還比較像是一個哭鬧的小孩。在她眼裡,抱頭蹲著的宗佑,還是當年那個被媽媽拋棄的小孩。

這個一樣是個浪漫化的版本。

2008年7月30日 星期三

Last Friends

由長澤雅美以及上野樹里主演的日劇 Last Friends是一部像女王教室那樣,那種讓正常人看了之後會有點受不了的日劇。不過沒有女王教室那麼誇張就是了。劇中的主題是家庭暴力以及心理精神上的問題。

長澤雅美飾演的美知留是家庭暴力的受害者。很標準的,這個角色會讓人從一開始的同情,漸漸因為她不斷原諒施暴者,變成讓人覺得有點不值得同情。而施暴者(美知留男友)宗佑的職業竟然還是在兒童福利課服務的公務員呢,這更讓人有種知法犯法的反差。

這樣的安排,如上所述,很標準。讓人覺得很寫實。如果只是這樣,也不過就是寫實而已。對我來說,Last Friends 讓我可以有點了解宗佑以及美知留這種典型的立場。

宗佑生病了。他的心生病了。由於幼年時他媽媽拋下他跟別的男人跑了,所以他從小都很孤單。有些有類似遭遇的人可以自我調適,但很不幸的,他沒能辦到這點。因此,他一直處於痛苦中,想要逃離這種孤單的狀況。他應該是一直幻想能夠找到一個適當的對象,組成一個家庭,生下小孩,然後讓小孩能有他過去沒有過的童年生活。

他找到的對象是美知留。但又由於從小缺少模仿及練習的對象,他與人相處的技巧和成熟度其實很有問題。跟美知留在一起他是幸福的,因為美知留了解他。即使他缺乏愛人的技術,他還是盡量模仿癡情男該有的動作。也許是看電影學的,有點戲劇化,但還有模有樣的。

由於極為害怕孤單,又由於小時候媽媽拋棄他,所以他極為害怕美知留拋下他跑掉。害怕的程度已經到達病態了。更大的問題是,由於他從小缺少學習相處技巧的機會,他不知道怎麼解決這個問題。他只有最本能最原始的方式,暴力。

他想要改善這個世界,他想要靠他的力量來辦到這件事情。這也就是他努力考上公務員,然後從事兒童福利工作的原因。他很聰明,知道很多手段。但是與人相處這種事情太難了,沒有經年累月的練習是不行的。由於他夠聰明,可以靠其他方法來彌補人際處理能力的短處,所以也活過這麼多年。但也因為這樣,造成他的人際處理能力更為弱化。這也就是為什麼他用了許多有「創意」的方式來處理溝通問題的原因(黑函、剪耳朵、站崗)。

2008年7月8日 星期二

到葉門釣鮭魚、鬱林湖失蹤紀事、Hyperion

這是我最近讀的三本小說。三本小說之間沒有直接的關聯,甚至可以說毫不相干,但在某種程度上又有微妙的相似之處。 「到葉門釣鮭魚」的故事主軸是英國政府的一個企圖在沙漠國家葉門中培育鮭魚的計畫。該書的賣點在於用會議記錄、公文、電子郵件、日記等等來構成內容。藉由這些在日常生活中出現應用文體,刻劃出背後的事件。比較文字與真實世界之間的異同,產生出趣味。比方同一場談判,從甲的日記是自己掌握全局,但從乙對上級的報告來說,又完全是另一回事。而看嚴肅的公文,其實是用來包裝「在沙漠中釣鮭魚」這樣瘋狂的計畫。而這個釣鮭魚的計畫再怎麼瘋狂,其荒謬程度也只是背後的利益分配與權謀鬥爭的冰山一角罷了。 但全書使用日記、電子郵件等等還是有局限性的。因為很多事情是不會被文字紀錄下來的。因此,作者只好讓書中的角色寫一些非常詳實的心情日記,寫一些寄不出去的信來補充人物的內心世界。這樣其實是有點遺憾的,因為難免會降低了書中偽文件的真實感。 不過使用文件紀錄這種文體來構成小說不是新鮮事。比方「鬱林湖失蹤紀事」也有約一半的篇幅是用偵訊調查報告的形式構成的。和「釣鮭魚」不同,「鬱林湖」用這種寫法的目的是要凸顯事實的不確定性。「鬱林湖」也描寫了一些政治生態,而它的主軸則是真實與謊言的界線。所以主角的魔術師與政客雙重身份也順理成章了。當世界充斥著巨大謊言,一些小謊話真的有那麼邪惡嗎?主角一生與謊言糾纏,最後終於逃脫了,從這個充滿謊言的世界中失蹤。但這個逃脫本身,似乎也是個謊言。 Hyperion 是科幻小說,雖然不是用應用文體構成的,但是書中以六個中篇故事組成,所以同樣的,可以從不同的觀點來說故事。 這六篇是六個聖徒為了打發旅程的無聊,講述各自的故事。可以拆開來看,每篇都自成一格,作者講故事講得很動人。但神奇的是六篇又相輔相成,合起來看後,就像把許多瞎子摸的象又組合在一起了。這六篇內容包含不同的科幻類型,神秘不可解的異星種族、高科技星際戰爭、地球末日詩篇、時光倒流的奇特科幻病、cyberpunk 類型的未來偵探、星際旅程有關的愛情浪漫傳奇。作者並不是在炫技,至少不完全是炫技。與「六個故事」「六個觀點」這個調性相呼應的,作者是要用不同面向來描述一個世界。有許多不同的科幻類型來描述未來,有些黑暗有些光明,有烏托邦有地獄,有些著重於網路虛擬世界,有些則著重於星際旅行。但未來到底是哪一種科幻類型所描述的? Hyperion 提出一個浪漫的答案:「都是,看你從什麼角度去看」同一個世界中,有電腦駭客和虛擬世界,也有未來的星際戰士、遨遊星際的商旅。對有些人來說,生活是地獄,對另一些人來說,可能是天堂。 武俠小說的是世界其實也有點類似,電影臥虎藏龍在某個程度上,也是用類似的方法帶我們進入一個武俠世界。你可以從保鑣武夫的角度來看草莽的江湖,可以看到煉氣化神、鍊神還虛的修道劍客江湖,可以看到塞外盜賊刀的的江湖,可以看到朝廷官府的江湖。 在「釣鮭魚」裡面來說,科學家眼中毫無價值得計畫,也許在政治外交上有實質的意義。從商人眼裡來看,這些也許都無關,現實收益才是唯一需要考慮的。「鬱林湖」中,客觀的現實事實有時並不存在,有的只是個人眼中不同的真實。 不約而同的,三本小說都沒有非常明確的結局。「釣鮭魚」的結局還算明確,不過太跳脫而突兀,有種不真實的感覺。曾經看似極為關鍵的計畫與人物,到頭來其實也可有可無。「鬱林湖」留下一個撲朔迷離的結局,讓人自行解讀。Hyperion 還有續集,不過以第一本單獨來看,故事動人就好,結局到底如何,誰在乎呢?

2008年6月17日 星期二

Project Euler 198 題

Project Euler 的 198 題。簡單的說,要算出分母在 10^8 以內,大小在 0~0.01 之間的「混淆數」總共有幾個 。而所謂的混淆數 x,是指如果對於某個 m,分母不超過 m 的「最近似 x 的分數」不只一個時,就稱 x 為混淆數。比方對於 x=9/40 來說,m=6 時, 1/5 和 1/4 都是分母不超過 6 最近似 x 的分數。
這個題目其實如果沒有任何基礎知識的話,還不太容易,所以解出的人不多。但站在一些基礎知識之上, 10^8 這種數量級是很容易用程式來秒殺的。據說 Knuth 的 The Art of Computer Programming 裡面就有提供相關的演算法。
不過使用 Haskell,可以很直接的用遞迴解出:

f a b l m | a*b>l || (a==1 && b > m)  = 0
         | otherwise = (f a c l m)+1+(f c b l m) where c=a+b
main = putStrLn $ show result
      where result= (f 1 100 l2 m) + 49+l2-m
      l = 10^8
      l2 = l `div` 2
      m = floor (sqrt (fromIntegral l2)
七行就簡單解決了。如果你知道背後的數學,上面的程式碼其實是很直接的。但用 Python 解就麻煩了,因為上面這個遞迴解超出 Python 的遞迴深度。可以用迴圈來取代遞迴,如下面的演算法:


def p198(M=10**8, z=100, cnt=0):
 M2=M/2
 a=m=int(M2**0.5)
 stack=range(z,m)
 while stack:
     b=stack[-1]
     if a*b>M2:
         a=stack.pop()
     else:
         cnt+=1
         stack.append(a+b)
 return cnt+M2-z/2
(程式碼我從 Project Euler 直接貼過來,排版有點亂掉)
這個演算法是我參考別人的解答後寫出的,配上 psyco 後,其實還挺巧妙也挺快的,但不太容易讀懂,要跟蹤一下堆疊是怎麼跑的。
但有些簡單的工作, Haskell 寫起來又很累贅。比方有一個整數 n,想找出它的根號的整數部份,如後印出來,在 python 來說再簡單不過的
print int(x**0.5).
Haskell 的作法要先將整數轉成浮點數,開根號,然後再用 floor 轉成整數,最後再用 show 轉成字串才能印出。所以是
putStrLn.show $ (floor . sqrt) (fromIntegral n)
如果有許多浮點數與整數,那更複雜一點的運算就要轉來轉去。雖說這樣可以強迫正確的設計風格,但有時只是簡單的小計算,這樣也未免太累了。
果然 Haskell 能將複雜工作簡單化,簡單工作複雜化。

2008年6月12日 星期四

程式設計語錄

圖片來源: wikipedia
(選自 DevTopics 整理的語錄)
(用來讓自己看起有學問的)
  • "Simplicity, carried to the extreme, becomes elegance."  簡單到極致即為優雅。
    – Jon Franklin
  • "The best way to predict the future is to implement it."  預測未來的最佳方式就是實做它。
    – David Heinemeier Hansson
  • "Make everything as simple as possible, but not simpler."   儘量讓事情簡化,但別太簡化。
    – Albert Einstein
  • "The difference between theory and practice is that in theory, there is no difference between theory and practice."  理論和實務的差別在於,理論上,理論和實務沒有分別。
    – Richard Moore
  • "The greatest enemy of knowledge is not ignorance, it is the illusion of knowledge."  知識的的敵人不是無知,而是知識的假象。
    – Stephen Hawking
  • "密碼就像內褲一樣: 不要讓別人看到,要常常更換,而且,別和陌生人共用."
    – Chris Pirillo
  • "Computers are like bikinis. They save people a lot of guesswork." 電腦就像比基尼,幫我們省下許多猜測的麻煩。
    (Sam Ewing)
  • "Come to think of it, there are already a million monkeys on a million typewriters, and Usenet is nothing like Shakespeare."  其實想想,現在已經有上百萬隻猴子坐在上百萬台打字機前了,但網路論壇一點也不像莎士比亞。(現在可用來描寫部落格)
    (Blair Houghton)
  • "Hardware: The parts of a computer system that can be kicked." 
    (Jeff Pesis)
  • "Web Services are like teenage sex. Everyone is talking about doing it, and those who are actually doing it are doing it badly." (網路服務) 
    – Michelle Bustamante
  • "The best way to get accurate information on Usenet is to post something wrong and wait for corrections."
    – Matthew Austern
程式師的幽默
  • 問:為什麼程式設計師是分不清萬聖節和聖誕節?
    答:因為 Oct 31 = Dec 25.
  • 一個男人在吸煙,他的女朋友很生氣的說:"Can't you see the warning on the cigarette pack? Smoking is hazardous to your health!" 男人回答說: "I am a programmer. We don't worry about warnings; we only worry about errors."
  • "I think Microsoft named .Net so it wouldn't show up in a Unix directory listing."
    (Oktal)
  • "C++ : Where friends have access to your private members."
    (Gavin Russell Baker)
  • "Computers are getting smarter all the time. Scientists tell us that soon they will be able to talk to us. (And by 'they', I mean 'computers'. I doubt scientists will ever be able to talk to us.)"
    (Dave Barry)
  • "I've noticed lately that the paranoid fear of computers becoming intelligent and taking over the world has almost entirely disappeared from the common culture. Near as I can tell, this coincides with the release of MS-DOS."
    (Larry DeLuca)
  • "It was a joke, okay? If we thought it would actually be used, we wouldn't have written it!"
    – Mark Andreesen, 談 HTML 的 BLINK 標籤

程式師與使用者
  • The three most dangerous things in the world are a programmer with a soldering iron, a hardware engineer with a software patch, and a user with an idea. - The Wizardry Compiled by Rick Cook
  • "If you think your users are idiots, only idiots will use it."
    – Linus Torvalds
  • "From a programmer's point of view, the user is a peripheral that types when you issue a read request."
    – P. Williams
  • "Computers are good at following instructions, but not at reading your mind."
    – Donald Knuth
  • "There is only one problem with common sense; it's not very common."
    – Milt Bryce
  • "Your most unhappy customers are your greatest source of learning."
    – Bill Gates
  • "There are only two industries that refer to their customers as 'users'."(販毒業與軟體業)
    (Edward Tufte)

  • "Any fool can use a computer. Many do."
    (Ted Nelson)
  • "That's the thing about people who think they hate computers. What they really hate is lousy programmers."
    (Larry Niven)
  • "Just remember: you're not a 'dummy,' no matter what those computer books claim. The real dummies are the people who–though technically expert–couldn't design hardware and software that's usable by normal consumers if their lives depended upon it."
    (Walter Mossberg)
  • "Software suppliers are trying to make their software packages more 'user-friendly'… Their best approach so far has been to take all the old brochures and stamp the words 'user-friendly' on the cover."
    (Bill Gates)
  • "There's an old story about the person who wished his computer were as easy to use as his telephone. That wish has come true, since I no longer know how to use my telephone."
    (Bjarne Stroustrup)
程式設計
  • (程式註解)"Commenting your code is like cleaning your bathroom — you never want to do it, but it really does create a more pleasant experience for you and your guests."
    – Ryan Campbell
  • "Low-level programming is good for the programmer's soul."
    – John Carmack
  • "A program is never less than 90% complete, and never more than 95% complete."
    – Terry Baker
  • "Manually managing blocks of memory in C is like juggling bars of soap in a prison shower: It's all fun and games until you forget about one of them."
    – anonymous Usenet use"
  • "Standards are always out of date. That's what makes them standards."
    – Alan Bennett
  • "There's no obfuscated Perl contest because it's pointless."
    – Jeff Polk
  • "Some people, when confronted with a problem, think 'I know, I'll use regular expressions.' Now they have two problems."
    – Jamie Zawinski
  • "You can't have great software without a great team, and most software teams behave like dysfunctional families."
    (Jim McCarthy)
  • "There are only two kinds of programming languages: those people always bitch about and those nobody uses."
    (Bjarne Stroustrup)

2008年6月10日 星期二

zhpy 的另類用法

配合上 zhpy ,我們可以寫出下面這樣的 python 程式:

# encoding: zhpy_utf8
from math import *
from operator import *
print Σ(range(100))
print sin(π/4) ≠ √(2)/2
print(100),(e)
print 5 × 30 ÷ 2 ≦ tan((5)*π/4)
Π=λ f:reduce(mul, f, 1)
print Π(range(1,6))
print set([1, 2, 3, 4, 5]) ∩ set([1, 3, 5, 7, 9])
(第一行是 MagicCodec 語法,普通的 zhpy 請去掉第一行)
不管實不實用,至少增加了一點可讀性。既然是λ,為什麼要寫成 lambda?
以上的程式碼只需要下面的 zhpy .ini 檔案(可以叫做 math.ini,放在執行的目錄下)
[math]
λ=lambda
π=pi
Σ=sum
≠=!=
÷=/
×=*
㏒=log10
㏑=log
√=sqrt
≧=>=
≦=<= ∩=& ∪=l
for 和 in 可以換成相對應的符號, set 的 <, <= 也可以換成 set 符號。
Haskell 的 ide Lesksah能做到這件事情。 如果能夠把 lyx 修改成 python, haskell 或者其他程式語言的編輯器,應該也挺有趣的。
相關的東西是 TeXmacs 的 python plugin tmPython

根號 2 到兩百萬位的挑戰

Sphere Online Judge 有一個題目是在 20 秒內計算根號 2,越多位越好(上限是兩百萬位)。有不少人能達到這個目標,但都是使用 C 或者 C++。我想試試看 python 這種以速度慢聞名的語言,能達到什麼程度。試驗的結果是十五萬位。雖然不太多,但是也擠進了排行榜裡面前二十名。而目前 python 語言的第二名還不到五萬位。

我的程式沒有用什麼特殊的技巧。事實上, python 的乘法不算太慢,現在 python 已經使用了 Karatsuba 演算法來做乘法,在一萬位以內的效能都還不錯,算到十幾萬位也都還能接受。但再上去就有點吃力了。而最主要的瓶頸在於 long 到 str 的轉換速度。光是將一個兩百萬位的數字轉成字串,就會花上非常久的時間。

改用 gmpy 會快很多,應該能夠算到百萬位以上,雖然我沒試過,但 spoj 應該不能使用 gmpy。

所以,也許應該直接寫個簡單的 FFT 乘法模組。事實上,我找到了一個叫做 DecInt 的 Pure python 套件,裡面實現了幾種快速的乘法及除法演算法,而且因為基本上資料是用十進位表示,數字轉字串非常快。他的乘法也許不是最快的,但是如果要我自己寫,大概也會是類似的東西,所以相當適合先拿來測試一下效能。

果然,大致上可以讓算十五萬位的速度快兩三倍。如果自己再強化改進,也許能再快個兩倍,但估計最多只能勉強上到百萬位,而且需要相當長時間的測試和實驗,所以我放棄。

於是我改用 Haskell 來寫。我沒有寫過 Haskell 程式(現在也還不會),而且連 Tutorial 都沒有讀完,就抓了 ghc 用最笨的方式把程式寫出來了。我只需要知道怎麼用 = 來定義函數能寫了。結果算到了一百六十萬位,足足比 python 多了十倍(Haskell 現在第二名約一百二十萬位)。如果再多加微調,或者我如果對 Haskell 再多熟悉一點,也許還能多個不少位,甚至到兩百萬位也不無可能。

其實我只要算到五十萬位,然後再用個 4-way Toom Cook 就行了,而算到四十萬位不用三秒。不過問題是,就像前面說得,其實我還不會寫 Haskell。

演算法基本上和 python 版本的相同,不過改以 recursive 的寫法。 Python 雖然完全支援 recursive 函數,但是 Python 的函數呼叫很慢,又限制層數(內定1000,最多 5000),所以,其實有點降低我把東西寫成遞迴的誘因。反之,Haskell 是 functional language,所以其實是獎勵這種寫法。

而 Haskell 之所以算得這麼快,其實有點勝之不武,因為 ghc 內建用 gmp 來做計算。

讓人疑惑的反而是,為什麼 python 不用 gmp 來做計算?

當演算法夠好,時間夠長, python 的速度劣勢就能被彌補,但 online judge 的時間限制都不太長,二十秒已經算是超級長的了,但這二十秒差不多只等於我電腦上的五、六秒,典型的時間限制是兩秒。用 pure python 實現很好的乘法演算法,也要到上萬位才能擊敗 python 內建的長整數乘法。所以,現在想用純 python(而且程式碼在4kb以內)上兩百萬位,還挺困難的,不過,也許還是有人能辦到也說不定。

(Update 2008-06-11) Haskell 達成兩百萬位。當然我 Haskell 的能力比兩天前進步一點,但主要還是用笨方法寫 recursive function。程式碼總共 11 行,而且其中有 3 行是用來定義一個函數,來達到 python 的 zfill 功能。

2008年6月1日 星期日

Euler 計畫和其他

前一陣註冊了 Project Euler,然後玩了一下裡面的題目。
Project Euler 蒐集了一系列的挑戰問題,這些問題的答案都是一個數字或者一組數字。每當你破解一個問題後,你就能與其他同樣破解這個問題的人,討論答案與心得。通常解決這問題需要一點程式設計技巧和數學知識。
網站裡面也會對於不同國家或者程式語言的解題者做統計和排名。比方說這是台灣的統計,而這是 Python 語言的統計。和「點點點」相比,台灣的表現很爛。
一般所謂的 online judge 系統其實很多,ACM 風格的 online judge 是主流。 UVa online judge 是其中的代表。其他還有如ZeroJudge
和 Project Euler 不同, Project Euler 上傳的是答案,而這類 online judge 要你上傳的是「程式」。所以有限定使用的程式語言。標準的語言是 C,C++,Java。雖然我也寫 C++和C,但我還是比較喜歡能自由選擇工具。這點到不是根本性的問題,像是 Sphere Online Judge 就能讓你使用許多不同的程式語言,包含 perl, ruby, python。
另外一個不同點是時間限制,雖然 Project Euler 也有所謂的「一分鐘法則」,就是程式應該要能在一分鐘跑完,但這不是硬性規定,真正的裁判是你自己。事實上,如果你喜歡(而且可以的話),你甚至可以 用google 找答案。真正的裁判是你自己。我喜歡這種風格。
一般的 online judge,有些題目有時間限制。就比賽而言,這提供競賽公平性的基準。但這個時間限制沒有「理論上的定義」,端看裁判主機端執行的時間而定。這缺乏了一點美感。
另外就是題目取向,Project Euler 的題目有時會需要一點數學知識,而一般程式競賽有時則是要一點演算法上的知識。而 Project Euler 容許的執行時間往往比較長一點。
總之,雖然都是程式挑戰題,但是風格和取向各有不同。
另外一種類型是 Code Golf,著重在用最短短的程式碼達成指定的功能,就像是打高爾夫一樣,你想要用最少的桿數完成比賽。雖然也是程式解題競賽,但又另有一番風格。
當然,寫程式的目的在於寫出「真正有用」的東西,而不是解答這些問題來炫耀自己有多強。但是,不管是哪一種風格的程式解題競賽,在你解題的過程,都能增進自己的程式設計能力。比方 Code Golf 裡面,有些解答是不可思議的短,在你追求這個目標的同時,才發現原來有些語言特性是自己之前忽略的,某種問題原來還有這種寫法。
(對 Project Euler 有興趣的朋友,可能也會對 IBM 的 Ponder This 有興趣。)

2008年5月29日 星期四

「昨天還夢到妳呢!」我說。才發現,仍然在夢裡。

2008年5月5日 星期一

突破性思考的小謎題

這個題目是從 PTT 上看到的:

作者  newtonapple (newton and apple)

阿基米德的浴缸-突破性思考的藝術與邏輯
作者:大衛‧伯金斯/著
譯者:林志懋
---------------- 正題開始--------------------------

兩個參賽者輪流挑選桌上寫桌上寫著有數字1到9的便條 紙,每次一人只能拿一張,看誰能搶在對手之前湊出來 任三個總合為15的數字,第一個參賽者先挑二,第二個 參賽者的最佳挑法為何??

還挺有趣的題目。在相信有「突破性思考」能解決的漂亮解答的前提下。花了我十分鐘左右才想到,而且還動手稍微算了一下。不過這類題目,花多久時間解答或是否被考倒,都無所謂,只是有趣而已,就像冷笑話一樣。

提示:(用滑鼠拉反白可看到)

井字棋、魔方陣。要動手確認一下三個數字能組成 15 的只有 (5,x,10-x) 和 (6,8,1) (6,2,7) (4,2,9) (4,8,3)
438
951
276

2008年5月4日 星期日

Python 算圓週率 這次算到無窮位

python 的 generator 很好用,理論上來說,可以表示無窮小數。而無窮小數的四則運算,可以用前面有限位來計算到一定的位數,所以,如果用 generator 生成的十進位展開,配合 operator +-*/ 等等,我們在 python 上可以弄出一個無窮精確的 real number class。
這樣,其實有點用有限的電腦來存放無窮位的資料的感覺。
這樣,我們可以很優雅的算出圓週率近似值到無窮位。
當然,速度一定很慢。反正太匆忙本來就不太優雅。
之前有看過利用類似概念來算圓周率的 python 程式,實在不錯。不過那個程式太長了,而且年代久遠,沒有用 operator 和 generator。
另一個好像叫做 accurate-math 的東西,也是可以做無窮位計算,不過呢,他的方法比較類似先固定算前一千位,然後等到需要一千零一位時,從頭開始算前兩千位。
像這種沒有實用價值的東西,用這麼醜的方法是不行的。
於是,我嘗試了一下寫一般性的 real number class ,才發現很麻煩(主要是 0.999...這類的問題)。而且, python 有 recursion 的 limit ,雖然可以改大一點,但再怎麼大也不是無窮位,除非用 stackless python。當然,可以避開不用 recursion,但程式結構就沒有那麼漂亮了。
所以就放棄,改成以算圓週率為目標。這樣,只需要簡單的除法、減法以及交錯級數就行。
結果需要三十幾行,跟之前只算固定位的三行比起來,差太遠了,不夠漂亮。
所以算是失敗,不過還是可以看看就是了。雖然超級慢,但是只要記憶體夠,可以一直跑到無窮位的圓週率。(這個程式碼的風格很糟,原本希望能夠用短短幾句話,很清楚的描述四則運算和交錯級數的計算,可惜失敗)

from itertools import *
import sys
# a/b 的無窮位小數展開
def
ldiv(a,b,p=0):
f=lambda x:x.append((x[0]%b)*10) or x.pop(0)/b
return iter(f.__get__([a*10**p]), -1)
# 比較上界ub 下界lb,然後將相同的位數傳回(p 是用來補前面的 0)
def digits(lb,ub,p):
u,l="%d"%ub, "%d"%lb
n,m=len(l),len(u)
common=takewhile(lambda i:l[i]==u[i], range(n))
return [] if m-n else chain(repeat(0, p-n), (int(l[i]) for i in common))
# 交錯級數計算(只算一個位數,要代入後面的模版)
def altseries(ub,lb, num, prec, a):
if num:
s, d=sum(a(i).next() for i in range(num-1)), a(num-1).next()
ub, lb= ub+s+max(d,0), lb+s+min(d,0)
for i in count(num):
d=a(i, prec).next()
if not d:
return ub, lb, i
ub,lb = (lb+d, lb) if d>0 else (ub, ub+d)
# 減法(只算一個位數,要代入後面的模版)
def subop(ub, lb, num, prec, a,b):
ub=lb+a.next()
return ub, ub-b.next(),1
# 減法以及交錯級數計算的模版
# 真正的上下界是 ub+num 和 lb-num
def opgen(ub,lb, num, precs, op, *a):
for prec in count():
ub,lb,num=op(ub*10,lb*10,num, prec, *a)
for x in digits(lb-num/2-1, ub+num/2+1, prec-precs):
yield x
precs+=1
ub,lb=[x%(10**(prec-precs)) for x in (ub,lb)]
# Pi 的交錯級數(其實是 pi(n) 是數列的第 n 項)
s=lambda k,p:opgen(0,0,0,-1,subop, ldiv(16, k*5**k, p), ldiv(4, k*239**k, p))
def pi(n, p=0, d={}):
return d.setdefault(n,imap(lambda x:-x, s(2*n+1,p)) if n%2 else s(2*n+1,p))
# 開始利用 generator 展開小數
for n in opgen(0,0,0,-1,altseries, pi):
sys.stdout.write("%d"%n)
sys.stdout.flush()
(原始碼)稍微修改,也能夠計算其他的交錯級數。

2008年4月26日 星期六

python shell-like pipe

像是 python generator tricks 一樣,其實不少人希望能在 python 裡面做 shell-like pipe。很明顯的,用 | operator 可以辦到這件事情,像是 ASPN Recipe: Shell-like data processing 就是一個例子。但缺點是要用一個 terminator 放在最後。此外,每個指令也都必須要加括號。所以,即使是簡單的 ls,也要變成 ls()|printlines 。而且,你要自己幫每個指令自己加上 __ror__。

PipeCmd

所以,我用三個方式來解決這些問題。最後的 __ror__,現在可以用 decorator 來處理了。terminator,我改用 __repr__ 來取代,這樣,在 python interactive shell 下,可以直接看到想要的回應。也因為如此,所有的資料都會被轉成 PipeOuput class (其實只是 iterator 加上 | 和 repr)。至於第一個問題,我用類似 partial function 的 class PiprCmd 來處理,有一個特別的 argument 稱為 stdin,用來代表 pipe input。

這樣,我們就可以
from pipeutils import *
ls|wc
ls|tail(n=5)|sort
cat/"*.py"|grep("def")
grep("pipe")/"*.py"/"/usr/include/*.h"
grep("^a","aaa\nbbb\nccc\nabc".splitlines(), open("text","rb"))
裡面的 / 是吃檔案名稱的,cat("text") 等於是 cat/"text",但是 cat/"text*" 等於 cat("text1", "text_something", ...)
更好的是,也可以和一般吃 iterator 的函數互相作用,也可以用一般 iterator 作用 (pmap 是把普通的的函數變成吃 iterator 的函數)
ls|(lambda g: (l.upper() for l in g))
"abcdefg"|pmap(mul,range(7))
import math
range(0,90,15)|pmap(lambda x:x*math.pi/180)|pmap(math.sin)
我的方法不算是最好的,應該只要用一個 class 就行。不過,這樣的解法很直覺。
其實用 ruby 會比 python 更像 shell,因為 ruby 函數呼叫可以不用括號。
另外把所有物件變成 file stream like 可能會更像 shell pipe的行為。
其實還挺多人想要把 python, ruby, perl 的強大功能跟 bash 這類 shell 混和。有一個 perl 的 project 就是把 unix 工具用 pure perl 實現。 python 也有很多,比方 shython 等等,python 本身也有 shutil, diff, 而 ipython 也有 shell-like 功能。
**Update: 20080426
改成只用一個 class pipecmd, 邏輯上比較簡潔一點。同時也做了一些處理,讓 cat(range(10))|sum 也可以跑。
**Update: 20080427
基本上一樣原理的 minipipe.py 只有 60行

2008年4月25日 星期五

Python 的 Generator Tricks

我們都知道 python 的 iterator很有趣,比方下面這個generator 能生成所有質數(根本就只是把質數的定義講一遍而已):

(n for n in itertools.count() if n>1 and not any(n%k==0 for k in range(2,n)))
比較複雜一點的費波納契數列 callable iterator
iter((lambda x:x.append(sum(x)) or x.pop(0)).__get__([1,1]),None)

我們也知道新的 send/yield 能夠玩出不少把戲,不過這篇簡報簡直把 generator 玩得爐火純青 Generator Tricks for System Programming

generator 根本就能夠當成 pipeline 來玩。

比方你有一組 log,最後一個欄位不是數字就是 ' -'(當成 0),你想算這些欄位的總和,原來你可能會寫成

wwwlog = open("access-log")
total = 0
for line in wwwlog:
bytestr = line.rsplit(None,1)[1]
if bytestr != '-':
total += int(bytestr)
print "Total",total
但用 generaotr 來思考
wwwlog = open("access-log")
bytecolumn = (line.rsplit(None,1)[1] for line in wwwlog)
bytes = (int(x) for x in bytecolumn if x != '-')
print "Total", sum(bytes)

優雅多了,而且從 pipeline 來看,反而更容易理解。

配合另外一個也很神的 generator_tools ,就能玩出更多把戲。

2008年4月19日 星期六

鹿男與美麗的奈良

這部片是Mr. Monkey推薦, 因為劇中主角玉木宏與綾瀨遙分別因此片獲得當季日劇的最佳男主角及最佳女配角獎。玉木宏飾演的小川孝信一位常在重要關頭失敗的倒楣人士, 例如小學時的武術比賽偏偏在比賽前受傷、考大學因為湊熱鬧掉到水池而沒法準時到考、出社會到公司報到那天公司宣佈倒閉, 最後只好回到原來的大學研究室, 但卻因與實驗室同儕相處不融洽被老師建議去奈良女子學院擔任臨時代課老師、臨走之前才發覺自己女朋友要跟實驗室的死對頭結婚了, 原因是覺得玉木宏太神經敏感了。儘管如此, 在抵達奈良的路途中還是發生大大小小的災難, 最後終於到達學校幫忙準備的宿舍, 與劇中其他兩位學校歷史老師藤原道子(綾瀨遙)、美術老師福原重久(佐佐木藏之介)開始新生活。

奈良是個具歷史意義的古城, 我也曾於1991年第一次的日本旅遊曾造訪過奈良東大寺, 對於寺中的漫走鹿群還有印象, 此劇即以鹿作為主題, 引伸出拯救日本免於富士山噴發災難神話故事。劇中的奈良女子學院有兩所姊妹校分別位於大阪、京都, 三所女子學院皆設在當地古城旁邊, 因此分別以該古城的守護動物鹿(奈良)、老鼠(大阪)、狐狸(京都)作為校徽,鹿、老鼠、狐狸為神話中大明神的手下, 傳說中大明神腳下踩著一隻大鯰魚, 大鯰魚每隔六十年就會蠢蠢欲動, 造成火山噴發及地震, 因此鹿、老鼠、狐狸輪流傳遞一個名為”三角”或”目”的神器來封印鯰魚的活動, 劇中設計的背景即為接近六十年轉換週期的日本, 時常發生地震, 富士山也被偵測到有再度噴發的危險, 為狐狸要將封印轉移給鹿的一年, 小川為鹿所選出來的人類, 有著要從狐狸手上拿回”三角”封印的傳遞手使命。

劇中會講話的鹿、被鹿做記號會從鏡中看到自己鹿臉 "憔悴並神經衰弱”的小川老師, 為此劇特別的地方。此外, 為接待新老師小川的歷史老師藤原, 於出遊時不斷介紹各古蹟名勝的歷史, 除了突顯藤原對歷史事務的熱愛外, 亦使此劇別富歷史教育意義。

2008年4月17日 星期四

今夜,我們瘋狂跳舞

又到了大水蟻兵團大軍壓境的季節了...

今天,夜晚是我們的

不在乎旁人鄙夷嫌惡,我們恣意狂歡,盡情飛舞

這一刻的燦爛與幸福,值得一生蟄伏與屈辱

曾經,在黑暗中匍匐,只有渴求的痛楚

今晚,我們拋開束縛,生命自己作主

黑暗中飛向光明的渴求,純如天使

燈光下意慾蔓延的身軀,輕若無骨

兩小時愛恨纏綿,三億年輪迴癡苦

在春雨中顫抖,羽翼如櫻花飄走

在星空下狂舞,直到粉身碎骨

從不奢想要活多久

只求能陪妳到日出,將光明好好看個清楚

然後,一夜濃情蜜意入夢,伴隨朝露化為春土

明日,我將死去

但今夜,我們瘋狂跳舞

2008年4月16日 星期三

不用擔心誰吃狗

前陣子看完 Neil Gaiman 的美國眾神後,又接著看了他的「煙與鏡」。可能是由於翻譯的緣故,感覺沒有美國眾神那麼有趣。但裡面還是有不少有趣的故事。
最近的韓國狗肉事件,各種意見都有。用極端化法則來思考,你總是可以用能吃牛肉的理由來吃狗肉,用不能吃人肉的理由來反對吃狗肉。所以,太過一般的論述是無效的。
不過,我舉韓國狗肉事件的原因不是要講道理,只是要說煙與鏡裡面的一個故事。我現在手上沒書,不過故事基本上是這樣:
十年前的一天早上,所有動物都消失了。
人們開始恐慌。
愛因斯坦說:沒有蜜蜂,人類只能活四年。
更何況是所有動物都不見了呢。
沒關係,我們還有嬰兒。
嬰兒不說話也不太動。
他們沒有智慧和靈魂,和動物植物一樣。
嬰兒的肉又嫩又好吃,沒有人懷念動物。
嬰兒皮有彈性有保暖,做成的衣服真舒適。
愛因斯坦錯了,只要有嬰兒,人類活多久都不是問題。
不過問題是,今天早上,所有嬰兒都消失了。
怎麼辦?我們要吃什麼?穿什麼?
不用擔心,我們一定會想到辦法。
因為人類很聰明,跟動物和嬰兒不一樣。
煙與鏡中的另外一個故事,一個老旅館服務生說,過去是有神的時代,電影明星就像是神一樣,有獨特的氣質,你一看就會知道。但電視發明後,就沒有神了,只有電視裡面的小人。他也看到很多電視裡面的小人跑來著旅館,但和過去的明星完全不一樣。
我懷疑這是否就是美國眾神的靈感來源之一。有點像是 Video killed the radio star 的感覺。
美國眾神說的就是新世界沒有神。有一些老的神,但是因為不再受到人們的崇拜與信賴,逐漸凋零。有一些新的神崛起(網路、電視),但這些新的神只不過是將來的舊神(鐵路、電報)。美國這個地方,不適合神居住。
當有人喊著自己是新世界的神,或者新世界不需要神,我想到的是日劇生徒諸君裡面的 3DT 和「我們不需要老師」。生徒諸君裡面的二年三班學生,在被原本崇拜與信賴老師出賣背叛後,產生對老師以及大人徹底的仇恨與恐懼。所以其中的三人組成 3DT 這個團體,接受同學的委託,保護同學。「也只有我們能夠保護大家了」3DT 常常對彼此這樣說。即使在一年後,完全不一樣的熱血老師來了,他們也還是完全不信任。他們不斷重複:「我們不需要老師」。
在舊神不再受到信賴的新時代,新的神將自己的身份隱藏在人群中。
因為他們分不出來神與偽神的差別,只好自己當起神。但是如果你連神與偽神都分不出來,你又怎麼能夠當一個好的神?這就是問題所在。
人是無法變成神的,就像美國眾神的設定一樣,人與神是兩種不同的生物。
但是當人比當神要好。神要靠其他人的崇拜才能生存,而人不用。主角 Shadow 這樣說。
到了生徒諸君最後,他們還是說「我們不需要老師」。但意義已經完全不同了。之前他們因為認為所有的老師都是壞的,所以乾脆通通都不要。最後他們已經因為好老師而成長了,所以不再需要老師了。
所以結論是:

為何人類不吃狗?只因人是神的狗。
為何人類不吃狗?擔心神吃祂的狗。
雖然說是寵物狗,難保主人換胃口。
希望大家都變狗,不需要神他們吼。
倘若大家都是狗,不用擔心誰吃狗。
頂多就是狗咬狗,不要人牽自己走。

2008年4月7日 星期一

Cyril 的 Believe

圖片來源: Wikipedia
昨天去看了 Cyril 的 Believe 魔術秀。
座位
雖然本來不是特別想去看,不過既然決定要去看,依照慣例,就要選好一點的位置。因此,我買的是 $4500 的票。事實證明,果然是不錯的選擇。因為 Cyril 的魔術大多是近距離的,距離太遠,只能盯著螢幕,失去臨場感。既然要看,就要選好一點的位置,不然倒不如回家看電視。不過呢,即使是第一排的觀眾,許多地方,仍然只能看螢幕,所以第一排反而不好,因為要抬頭看。我坐第七排,位置適中。
Cyril 為了彌補近距離需要螢幕的缺憾,常常下來走動,所以坐在前面還是有好處的。
如果坐在前面,主秀魚缸魔術是可以不需要攝影機就能看到的。
不過整體來說, Cyril 的街頭魔術風格的魔術不適合在這種場合表演。因此,這場演出中,Cyril 穿插了不少舞台和 Party 魔術。
翻譯
翻譯水準普通,跟平常一樣爛。很多地方翻錯。比方說,有一段是 Tony's bar, 這個程序分成兩階段。第一個階段, Cyril 表演猜出觀眾選的牌。為了襯托第二段的神奇, Cyril 基本上只是用職業的水準簡單的執行這個魔術。表演完第一階段後,Cyril 說「剛才的這個魔術其實很難,但是因為現在魔術資訊太發達,觀眾的胃口變大,所以觀眾不會特別欣賞這個魔術。」但是翻譯在 Cyril 說完第一句之後,翻譯翻成「等下(第二階段)的這個魔術會更加困難神奇」。可想而知,接下來的翻譯只好混過去。
另外在主秀水族箱魔術,Cyril 講了一個笑話,說他畫在魚缸上面的魚的名字叫做大白鯊( Jaws)。這個沒有被翻出來,所以只看到 Cyril 做出誇張的肢體和表情,而現場沒有反應。
而在一個情色雙關語風格的魔術裡面,Cyril 拿著繩子問男性觀眾一個問題,翻譯翻的是「請問你喜歡繩子(rope)嗎?」不過我聽起來像是「你想歡角色扮演(role play)嗎?」我不很確定我聽到的是對的,但配合後面兩個洋妞的動作,以及後面的劇情,假如 Cyril 說的不是角色扮演,那他應該說角色扮演(用 BDSM 就太過頭了點)。
當然這樣也有個好處,從翻譯的流暢度可以當成線索,判斷哪些是事先設計好的橋段。
不過撇開翻譯的正確或者錯誤,翻譯的主持能力和臨場反應倒是不錯。
優點
應該說是,我喜歡的部份。
我喜歡那個鞋子清洗器的程序。他請了一位小朋友上台幫忙,而且充分發揮了小朋友的功能。隱藏魔術機關的劇情(將動作合理化),我很喜歡。
主秀魚缸程序,我也很喜歡。主要的優點是情境設計,以及與請上來的觀眾之間的互動。除此之外,還與前面表演的跳帕做了連接。
最後最後的雪花表演,雖然不新鮮,但是我覺得他做得很漂亮。舞台魔術中香煙和錢的部份也不錯,我喜歡他的舞台肢體風格。
謝幕的變人效果也很好。
缺點
第一個缺點是近距離的魔術不適合在這麼大的場合表演。偶而穿插可以,已魔術師為觀眾的場合可以,但是不適合當成以一般觀眾為對象表演裡面的主軸。所以, Cyril 盡量穿插了其他類型的魔術,像是大道具類型的。但這些魔術沒有什麼新奇之處,也沒有展現 Cyril 的魅力。
第二個缺點是,失手。在我看的這場表演中, 在表演舞台魔術時,Cyril 失手了。而這個失手是連外行人都看得出來的。因此,他的表演被迫中斷,他被迫比出手勢,要音控停止音樂(更尷尬的是,他手勢比了很久,我比音控師還早五六秒鐘看懂他的手勢)。事實上,他在更早一點的時候就已經有失誤了,只是這個失誤外行人應該看不出來。而稍後,他表演撲克牌魔術時,手法很不熟練,我懷疑他是因為之前的失誤而臨時補上的。
第三個缺點,是與觀眾的互動。我覺得他有點過度利用觀眾。比方說,請女觀眾上台來之後,先是親了女觀眾臉頰一下,然後坐手勢要女觀眾回親。就在女觀眾要親下的時候,他故意轉頭,讓女觀眾親到嘴巴。親臉頰那些都 OK。但是後來轉頭那個動作,一方面破壞了觀眾與魔術師之間的信任,另外一方面,讓上來幫忙的觀眾尷尬。雖然他有確認過那位女觀眾旁邊坐的不是她男朋友,但我仍然認為這樣是犧牲觀眾來換取效果。而這不是單一事件。他常常利用發聲權不對等的狀況來製造效果。雖然這個手法很常見,但是我覺得他利用得有點過頭,會造成被利用的觀眾有點尷尬。雖然這只是我的看法,不過至少對我來說,已經破壞了他街頭魔術那種比較親和的形象。
結論
不是非看不可,但也不算太差。我認為坐最好區, $2500 是合理的價錢。

2008年3月18日 星期二

那一棒的鋒情

六局下半,兩人出局,一壘有人,一比零,我們還落後一分。

時間是 2007年 12月 3日,中華隊在亞錦賽對上日本,爭取僅有的一張奧運門票。

日本的投手是王牌達比修有。

這時,輪到陳金鋒上場打擊。他在義大利世錦賽拿到全壘打王,已經是十年前的事了。

就像很多其他人一樣,我也在電視前觀看這場比賽。而那種既期待又怕受傷害的感覺又再度出現。期待陳金鋒再度成為救世主,但也很害怕他被三振或接殺。

和很多人一樣,我也有很長的一段日子,窩在廉價租來的小房間,吃的是僅能果腹的食物。那段時間,陳金鋒也在美國職棒大小聯盟間載浮載沉,雖然沉的時候要比浮的時候多些。小聯盟的待遇並不好,但那時早已是國民英雄的他,卻甘之如飴。

和很多人一樣,我時常會注意他的新聞,有時是好消息,其他時候則不是。每當發現他又沒打擊機會甚至又回 3A,雖然不見得完全理性,但常常會埋怨道奇總教練崔西有眼不識英雄,不多給一點機會。

但不管是好新聞還是壞新聞,和很多人一樣,總是期待多看到他的消息。因為只要看到他的出現,再爛的租屋與食物都不算什麼了。他讓我們回想起付出這一切的理由,讓我們記起自己的夢。而每個人的夢想都和他想進入大聯盟的夢想一樣重要。

未來就像投手投出的下一球,你無法預測會是什麼球路。但反正球來就打!也許我們不知道球會怎麼來,可是只要陳金鋒上場,我們永遠知道球要往哪裡去。

所以陳金鋒上大聯盟的時間,我們去道奇看球的頻率就會增加,希望能剛好看到他上場。雖然我們並沒有抱太大希望,因為你也知道,他上場的次數並不多。但還真有那麼一次,我們碰到了。八局上半,陳金鋒上場守右外野。雖然看得有點心驚膽跳,但這次他的守備稱職。九局下道奇進攻,還落後一分,終於快要輪到陳金鋒打擊了。一人出局,一壘有人,打擊的是來自韓國的崔熙燮,陳金鋒在旁邊暖身。我們的劇本當然是崔熙燮上壘後,陳金鋒至少擊出個打點甚至再見全壘打。如果崔熙燮不幸出局,那就是典型的陳金鋒時刻,也該是時候讓道奇的球迷見識救世主的風采了!

全壘打果然出現了,不過是由崔熙燮打出。全場球迷的歡呼雷動。這些歡呼聲裡面,有不少是韓國球迷發出的吧?不知道他們有多高興。我們心裡都默默這樣想。

2005年,我的生活條件變好了不少,而陳金鋒也終於回到台灣家人的身邊快樂的打棒球了。經過七年的辛苦,他終究還是沒能站穩大聯盟。十年前他拿到全壘打王的那屆世錦賽,他在預賽裡創出連四場五隻全壘打的新紀錄。但中華隊預賽就被淘汰,僅得第十三名,有史以來最慘的成績。似乎默默告訴我們這位國民英雄的人生將有帶著悲劇色彩的一面。回到台灣打職棒固然快樂,但缺少了美國職棒激烈的競爭,他對快速球勢必會生疏許多。

事實上,2006年亞洲職棒大賽,面對達比修有的快速球,他吞下 2K。大家都在想,如果他繼續留在美國,結果是否會不一樣?也因此,當陳金鋒上場時,以往只有單純的期待與相信,現在慢慢參雜了一份擔憂。擔憂的感覺慢慢變強,強到甚至某一部份的我,希望他能保送上壘或隨便打個鳥安吧。與其說是不想見到救世主的形象被破壞,不如說不想看到夢想在現實殘酷下幻滅。

回到六局下半。陳金鋒慢慢站上打擊區。和道奇球場那次一樣,壘上有人,兩人出局,落後一分。不同的是,這次,他等到救世主時刻了。問題是,對方的投手可是曾讓他吞下 2K 的達比修有。一年不見,年輕的達比修有正逐漸往頂峰邁進,年輕帥氣的他,來台時成了小女生追逐的偶像。而陳金鋒呢?

然後,我看到他的眼神。突然之間,我有種無法形容的感覺。硬要形容,就像是那種宣稱世界末日的瘋狂預言家附身一樣那種感覺。只不過,這次瘋狂預言家喊的是救世主降臨。不是那種又期待又怕受傷害的感覺,也不是過去那種單純的期待與希望,而是「一定」。他一定會打出全壘打。不是期待或相信,而是絕對的知道。幾球糾纏之後,那個瘋子叫的只是越來越大聲,果然:

球飛出去了,球飛出去了!兩分砲,我們反而領先了。這時候的心情,我想,如果你那時也有看到,你也同樣感受到了。

當然,既然你有看到,你也知道後來發生了什麼事。最後,我們10:2 慘敗。最後幾局,許多球迷都不忍卒睹。那張奧運門票,最後也讓日本拿去了。

時間拉到 2008 年八搶三奧運資格賽,中加之戰,八局下半,四比二我們還落後兩分,兩人出局,一二壘有人,輪到打擊的是有小陳金鋒之稱的羅國輝。

這是我們最後一次爭取奧運門票的機會。陳金鋒因為受傷,沒有參加。沒有陳金峰的中華隊,是一支年輕的充滿新血的球隊。前三場我們三連勝,不過,硬仗從這場才真正開始。事實上呢,因為加拿大比較強,我們鎖定的其實是下一場的澳洲隊。這隻年輕的隊伍,能夠緊咬著強隊加拿大不放,已經讓人對他另眼相看了。

同樣的救世主時刻,但場上的不是陳金鋒。我對羅國輝並沒有特別的期待。不要誤會,我知道他很強,也非常期待並且希望他能打出全壘打。只是相比之下,這個期待並不特別而已。畢竟,他不是陳金鋒。

直到看到他的眼神,我才知道我有多錯。因為,那是陳金鋒對上達比修有的眼神。我很確定,因為那個瘋狂預言家又跑出來了。「一定,這是一定救世主降臨的時刻!」

接下來發生的事情,就看影片吧:

果然,救世主降臨,球四平八穩飛出去了!5:4,我們領先了。只要再撐一個半局,我們就贏了!不過,就像中日戰一樣,我們又被逆轉了。但是這次不一樣,他們與加拿大奮戰到延長加賽,才以 6:5 一分之差飲恨。

他們說,要帶陳金鋒賢拜到北京。

當陳金鋒回來打球的時候,我們說能夠打過大聯盟,夢想已經達成。我們說,追夢本身就是一切。我們說,夠了,你付出夠多了,該是回到家人身邊快樂打球的時候了。但是,說沒有完全遺憾是騙人的。

直到今天,我才了解之前的想法有多膚淺。夢想從來就沒有遺憾。陳金鋒的夢想已經傳承到這隻年輕的隊伍上了。

這幾年,陳金鋒已經用他的行動,默默的影響了所有人,他的隊友們,學弟們,球迷們,所有台灣人。甚至也許,他的對手們。這個勇敢追夢的精神,已經深深地影響了每一個人。夢想的傳承,從來沒有斷過,從紅葉開始到世界盃、亞洲杯、奧運各項國際賽,從成棒到職棒的分分合合、從往日職發展到往美國發展,這個傳承,一代接著一代,從來沒有斷過,而且逐漸茁壯。我們見證了陳金鋒將他隊棒球的體悟,傳遞給年輕的後輩。

如果說奧運象徵人類對於夢想的追求,那麼,他們帶去的不是陳金鋒,而是我們每一個人。

每一天,你在自己的崗位上辛勤奮戰,為了自己的夢想而努力,就像所有的上班族、業務員、學生、生意人、工人或者任一個人。早上出門途中,買早餐時和老闆娘互道謝謝。謝謝你買我的早餐。謝謝你努力做的早餐。謝謝早上的太陽。謝謝中華隊。今天也要努力喔。

藉由短暫的接觸,堅守崗位、努力追夢的信念。在每個人之間傳遞著。

所以我們不會忘記,球要往哪裡去。

有一隻球隊,數十年來,將我們的夢想代代傳承。有人叫他中華隊,有人叫他台灣隊,但從沒有人為此爭執。因為我們知道,我們支持的是同一隊。

有一個人,在自己崗位堅持,埋頭耕耘。他是陳金鋒,他也是你我。也許講到台灣之光,人們第一個想到的不是他。但我們知道,只要我們都努力照亮身旁的人,台灣就會閃亮耀眼。

延伸閱讀:遷徙的冠羽: 帶陳金鋒去北京

2008年3月5日 星期三

中文程式語言

每次一提到中文程式語言,常常會看到人批評「中文程式語言」不實用,浪費時間。

「程式裡面用的英文很簡單啦,不會造成困擾」

「打英文還比較快」

沒有錯,對「一般人」來說,也許的確不實用。

大部分的人都把自己當成是「一般人」(常常也沒有錯),但是忽略掉自己前面和後面都還有人。

同樣的那群「一般人」,他們會偏好中文的文件和軟體,也會感謝翻譯成中文化的作者。

如果單從我自己的角度來看,中文化根本沒必要,浪費時間。因為「文件中用的英文很簡單,不會造成困擾」、「直接看英文還比較快」。

而我的英文還很爛呢。

如果連我都覺得中文化翻譯都是沒有意義、浪費時間,更何況是對英文程度正常的人來說?

還好,不是每個人都只從自己的需求來看世界。

那些想磨練英文而翻譯的人不談(其實翻譯品質堪慮),中文化的工作者本身往往不需要這些中文化文件和軟體的,他們是為了別人而做的。

「一般人」的確需要感謝那些翻譯者,感謝他們不像「一般人」一樣,只因自己不需要,就認為浪費時間、不實用。

很明顯的,發展中文程式語言的人,也不是因為自己需要才發展的。

前幾天到我家裝潢,弄電路、音響的人,有些甚至連 In, Out 這麼簡單的字, 都不是很確定。以前當兵的同袍,英文的程度也是遠低於我的預料。他們才是真正的一般人。

但我認為他們其實都很聰明,如果有適當的環境,如果程式可以用中文寫,他們也許就能學會寫程式。

這是我關心中文程式語言的初衷。即使遠在當兵之前,我還過份高估一般人英文程度的時候也一樣。

因為我知道,這個世界很大,有很多不同的人,很多狀況會出乎我預料。

比方,我也實在不知道 OOPS 開放課程計畫的中文翻譯到底要給誰看。

我無法想像能有多少人能學習高等課程,卻看不懂英文。我無法想像有人需要這套計畫。

我反而能想像那種因為是中文,而望文生義誤解的人(推翻相對論,滿口量子能量場、證明尺規三分角的那類人)。

但同樣的,我知道世界上的人有千百種,如果要我下注,我還是會站在有人需要那邊。

2008年3月3日 星期一

James Dean 語錄

(照片來源: wikipedia)
James Dean,雖然過世很久,但是作為美國通俗文化的一個象徵,還是大家耳熟能詳的名字。
我當然也知道這位二十四歲早逝的電影明星,不過也只是模模糊糊的知道而已。
直到後來,發現了一些他的語錄,才驚訝到注意到一個不到二十四歲的人居然說過這麼深刻的話。
後來想想,大概很多是電影台詞吧?不過,還是不減這些名言的有趣性。

  • "Dream as if you'll live forever, live as if you'll die today.” 這句是他的經典名句。
  • “Only the Gentle are truly strong.” 厲害的人,都很溫柔呢。James Dean 的名句比漫畫早得多。
  • “I want to be a Texan 24 hours a day”
  • “Rebel Without a Cause.” 應該是電影片名
  • “Eternity? ... That is one hell of a movie.”
  • "There is no way to be truly great in this world. We are all impaled on the crook of conditioning. A fish that is in the water has no choice that he is. Genius would have it that we swim in sand. We are fish and we drown."
  • "And my heart just did a flip-flop over that."

2008年3月2日 星期日

用 30 行 ruby 寫俄羅斯方塊

學一種程式語言,第一步是先跟著 Tutorial 走一遍。
然後,找到參考手冊,因為,這是你的救生圈。像是 Python 的文件就寫得相當清楚。
所以,我無法理解那些在網路上問一些官方文件就有答案的問題的人。如果一個人看不懂文件上那麼清楚的文字,那表示他閱讀能力有問題。那他又怎麼能夠讀懂網友回答的文字?
現在學 ruby,文件風格和 python 有很大不同,但是也非常清楚有用。
當然,光是這樣還不夠,還要真的寫幾個程式才能算數。
至於要寫哪些程式呢?每個人都有自己喜好。就我來說,以前,每學一種 GUI framework 或者語言,我會寫一個 Ansi Terminal Emulator。更早一點,還沒有 GUI 的時候,碰到新的系統,會寫個簡單的畫圖程式和簡單的中文系統 Viewer。
這有點像是一種儀式,如同成年禮一樣,你學程式語言的成年禮。寫完這一個中小型的計畫,就能說自己會一種語言了。
不過我學 Python 的時候,倒是沒有什麼成年禮。因為 Python 實在太好學了,差不多是看到就會了。勉強要說的話,就是之前那個 Alpha-Beta Search 系統。
但這也就是為什麼我 Python 的程式設計能力不太紮實的緣故。後來用 Python 寫了一些短的的俄羅斯方塊,才體會到這點。
所以,現在我學 Ruby 時,也打算把俄羅斯方塊當成是成年禮的一部分。以下就是用 ruby 寫的 29 行俄羅斯方塊。


require "tk"
W,H,Blk=40,40,{0xf=>"red",0x2e=>"#0f0",0x27=>"blue",0x47=>"#ff0",
0x66=>"#0ff",0xC6=>"#38f",0x6C=>"#f0f", 0=>"#000"}
Bkeys=Blk.keys.select{|x| x!=0}
new_piece= proc{ proc{|pc| {:a=>(0..16).select{|i|(pc>>i)&1>0}.map!{|i|
[(i>>2)+1,i&3]},:i=>3,:j=> -2,:c=>pc}}.call Bkeys[rand(Bkeys.length)]}
def collide(na,ni,nj)
na.map {|n| true if @board[nj+n[1]][ni+n[0]]!=0}.include? true
end
def redraw
@canvas.delete "all"
@board.each_with_index{|b,j| b.each_with_index {|c,i|
TkcRectangle.new(@canvas, i*W, j*H, i*W+W,j*H+H,
'fill'=>Blk[@p[:a].include?([i-@p[:i],j-@p[:j]])? @p[:c]: c])}}
end
@score, @bw, @bh, @p = 0, 10, 20, new_piece.call
@board=Array.new(@bh+3){|j| j!=@bh ? [0]*@bw+[15]*3:[15]*(@bw+2)+[0]}
(@canvas=TkCanvas.new :width=>@bw*W,:height=>@bh*H).pack
TkRoot.new.bind("Any-Key") { |e| na,ni,nj=@p[:a],@p[:i],@p[:j]
ni+= e.keysym=="Left" ? -1:(e.keysym=="Right" ? 1:0)
na=na.map{|n| [n[1],3-n[0]]} if e.keysym=="Up"
nj+=1 if e.keysym=="Down"
@p[:a],@p[:i],@p[:j]=na,ni,nj unless collide na,ni,nj
redraw}
TkTimer.new(200,-1){|e| !(collide(@p[:a],@p[:i],@p[:j]+1) or !(@p[:j]+=1)) or
proc{ @p[:a].each{|n| @board[n[1]+@p[:j]][n[0]+@p[:i]]=@p[:c]}
@board=@board.inject([]){|a,l| l.include?(0)? a+[l]:[[0]*@bw+[15]*3]+a}
@p[:j]<0 ? exit : @p=new_piece.call}.call
redraw}.start(0).mainloop
這個比 python 的 tk 版要短,不過可讀性差多了。
原來寫的可讀性比較高,最開始甚至還有定義一組 class,不過行數大約是五十行。
後來不用 class,就變成 40行以內,然後再進一步犧牲一點可讀性,就降到了三十行以內。
ruby 高手可能可以找到不少以上程式碼的可笑錯誤吧!
ruby 和 python 的比較一直是個熱門話題,不過呢,我得先要等我更了解一點 ruby 再說。

2008年2月14日 星期四

充氣娃娃之戀


最近一個月看了不少電影,
  • 色戒
  • 練習曲
  • 變形金剛
  • 男孩不壞 Superbad
  • C+偵探
  • There will be blood
  • The Eye: 美國版見鬼,本來要看 Cloverfield,但是 imdb 的時間表不太正確。
  • 蜂電影 Bee Movie
  • 誰才是導演 Clash of Egos/Sprængfarlig bombe : 丹麥片
  • 充氣娃娃之戀 Lars and the Real Girl
很多是飛機上看的,其中 Superbad 和誰才是導演都很不錯,色戒、練習曲、變形金剛都不用說。There will be blood 評價兩極化,看之前要有心理準備,C+偵探的風格還挺有趣的, The Eye 放鬆心情看,還是能達到娛樂效果。
不過這裡我要推薦的是充氣娃娃之戀。
影片簡介很簡單:害羞內向的 Lars,向他的哥哥和大嫂介紹他的女友。見面之後,發現居然是一個充氣娃娃。而 Lars 卻完全把充氣娃娃當成真人一樣對待(把她當人看)。在這個純樸的小鎮上,大家會怎麼看待這件事情呢?
光是看到片名,大家聯想到的可能是下面這段(娶充氣娃娃為妻的日本人)

即使不往變態片的方向想,想像的大概也是類似男孩不壞、四十歲處男、Knocked up 或美國派這樣的內容。
實際上,這部片子是極為溫馨的片子,是一部傑作。我不是說美國派、四十歲處男、男孩不壞
這些不好,只是說這部片子走的是更加內斂而溫情的路線。
裡面不乏簡單卻又讓人驚豔、發人深省的台詞和情節,像是冰凍的腳(你要看電影)的那一段話,或者是把(相對)正常的嗜好 action figure、絨毛玩具、寵物等等,拿來和把充氣娃娃當真人相比。
某些的情境下,人們不也嚐嚐把感情寄託在寵物、玩偶上嗎?將他們擬人化嗎?不也常常對虛擬的小說、電影人物,媒體塑造出的偶像賦予情感嗎?我們有什麼理由說 Lars 是不正常的?
(雖然說也有很多文化會把迷戀偶像、漫畫、action figures視為怪胎,也有 crazy cat lady一詞)但電影裡更多的是沒有文字的場景,一個眼神、一個表情、一個動作,傳達出許多只能意會的感動和情感。
所以不要被片名誤導了,這是一部相當好的電影。

有關修改周蟒的動機

gasolin 在他的回應中,有一段話:
但同時警覺到: 讓人寧願自己修改而不是發個 patch 給我們,也表示周蟒還有不足之處。
讓我覺得我需要稍微解釋一下我修改的動機。
拿 zhpy 當 MagicCodec 的一個模組,是目的。看到 zhpy 包含 pyparsing 之後,我就知道我必須要修改一下才能使用,因為 PyLua 裡面已經用到了 Ply ,再包一個 pyparsing 太重複了。
而且我知道 zhpy 的功能只需要 tokenizing 就夠了。所以一開始就準備把 pyparsing 去掉,換成標準的 regex。
當然將命令列換成 MagicCodec 是初衷,既然現在要刪掉 pyparsing,就順便把一些不要的功能刪除,然後把 Interactive interpreter 換成 PyOS_Readline hook , exception handling 換成 hook。
看了程式碼後,因為身為一個設計師的天性,自然會有很多意見,包含風格和功能性。其中風格主要是一些程式碼審美觀(程式碼重複),而功能性包括zh_exec 的功能性, 還有翻譯字典的編碼(utf8 str or unicode)。
有關風格和功能性的選擇上,帶有主觀的設計選擇成分,雖然說(依照定義)我認為我的選擇較好,但是我也可以理解別種想法的可能性。我也有一些「不好」的選擇,包含會用一些 python 2.5 才有的語法,在 python 3k 不向下相容之際,有點尷尬。但我的辯解是 python 3k 可以直接用中文當變數名稱(*), zhpy 在 python 3k 下本來功能性就有不同的目的,所以也不算太尷尬。
那為什麼不考慮 python 2.4 2.3 的使用者呢?一來 python 2.5/2.6 的壽命會很久(因為沒有 2.7),二來我認為除非付出現在 30 倍以上的努力(推廣和設計),中文程式設計不會真的有實際用途。在推出試驗機型 prototype 時,這些不是我需要關心的事情。
gasolin 寫 zhpy 的目的和想法顯然不同。而我的目標對象根本就不是 end user,這也就是我連 distutil setup 都不提供的原因。因為整個設計取向不同,所以我拿原來的 zhpy code 來 refactoring,而不是 直接利用。因此也談不上 patch 原來的 zhpy 的 code,因為修改後的 zhpy 和原來的 zhpy 本來就是為了不同目的的產物。
我要設計一台飛天車,拿一台量產的車子當基礎來修改,但不代表原來的量產車也要加上翅膀。


(*)理論上, python 2.x 不能用中文變數名,不完全算是 python 的問題,而是中文字到底哪些算是字母的問題。 python 2.x 是用 isalpha 和 isalnum 來判斷合法名稱的,而這些和 LC_CTYPE 有關。理論上,可以修改 glibc locale 設定的 LC_CTYPE或者用 vista 的 custom locale builder 來告訴 python 哪些算是「字母」。

2008年2月7日 星期四

Python MagicCodec 0.1(更新到 0.11)

這個是基於 PEP 263 弄的 python meta programming 小玩意。
包含兩個神奇編碼 zhpy 跟 PyLua。 MagicCodec 0.1 Download
(*更新 0.11)
安裝玩 MagicCodec 之後,下面這段會變成完全合法的 Python 程式
# encoding: zhpy_utf8
吼叫="啦啦啦"
印出 吼叫
執行 '印出 "再%s一次"%吼叫'
這個也是
# encoding: lua
i=10
function run(func) repeat func() until i==0 end
run(function () print("Hello!",i) i=i-1 end)
直接用 python 執行,或者用滑鼠點 xxx.py 就可以執行了。
MagicCodec 裡面包含的 zhpy 基於 zhpy 1.4,但是大量修改過了(幾乎全部改掉)。
有幾個修改的重點:
  1. 直接用 re 來做 tokenizer。殺雞不用牛刀,原來的 zhpy 用 pyparsing 。雖然說 pyparsing 提供很方便的功能來分解字串,但是類似的功能直接參考 python bnf 用 re.sub 來做,反而更簡單。
  2. 改掉許多重複的程式碼。原來 zhpy 有非常多的程式碼,重複好幾次。tw 的了一個函數,cn 的又寫一個函數。這樣維護起來很難。
  3. zh_exec 的功能和 exec 不同。我將他改成了比較符合原來 exec 行為的程式碼。改完後,原來的 zhpy_commandline 會爛掉,但實際上,會爛掉反而是 exec 的正確行為。
  4. 「執行 」我還是直接翻成 「exec zhpy.dec <<」,因為 zh_exec 是函數,跟指令 exec 的語法不同。
  5. type(x) == type("") 這類, 改成 isinstance(x,str)
另外一個重要的不同是改以 source code encoding 導向,將 zhpy 視為 python 的一個 codec,而不是另外一個 python 的實做。所以有許多差異。
  1. 用 MagicCodec 取代 zhpy_commandline,因為直接用 python xxx.py 就能執行了。而不用 zhpy xxx.py
  2. 用 excepthook 取代 try_run。
  3. 另外增加 PyOS_Readline hook,這樣 python 的命令列可以直接變成 zhpy 的命令列。所以取代原來執行 zhpy ,改用執行 python ,然後你 import zhpy.hooks;zhpy.hooks.setup_all() 就可以直接執行中文的程式碼。
  4. python win 也行,用前面的 zhpy.hooks 就可以了。
  5. idle 不行。因為 idel 是分離式的。如果你在 MagicCodec 的 __init__ 或者執行 idle 前執行 zhpy.hooks.setup_all(),就可以。
  6. idle 編輯器讀取 zhpy codec 的程式碼會解碼。所以會有問題。(所以 MagicCodec 也不永遠比較好)
  7. import 比較單純。原來 zhpy import hook 就不錯了。但是現在更好,因為不用修改, python 就能直接 import zhpy 的 module。原因很簡單,因為有 MagicCodec 之後的 zhpy 程式碼是合法的 python 程式碼。
但是還是有很多東西不行。
像是
# encoding: zhpy_utf8
吼叫="啦啦啦"
印出 吼叫
執行 '印出 "再%(吼叫)s一次"%locals()'
就會失敗,這個不難解決,只要用另外的 hook 包住 locals, globals, setattr, getattr 等。__dict__比較麻煩一點,這個是 mataclass 可以hook的。


更新(2008-02-28):由於網友 tocer 的反應,找到了好幾個 bug。
我其實有好幾個 Ubuntu 的機器,不過之前太懶,所以都沒有測試過。
所以雖然有考慮到, Linux 應該會有的狀況,不過都是用「想的」。
我們都知道,寫程式這樣是不行的。一測之下,果然 bug 連連。
第一個問題是好幾個檔案的權限設定有問題,windows 下還好, linux 下一般使用者就出問題了。
第二點主要是 encoded file 的問題。裡面幾個 return,雖然我是用很保守的 hook 法,但至少要傳回一些東西吧!另外還有一個語意上面的 bug 就是了。就是因為我要用保守的方式,只 hook,真正原始 file 形式的 sys.stdout/sys.stderr。所以語意應該是
if type(f) !=file: return f
才對,而不是
if type(f)==file: return
至於為什麼原來在 cygwin 上可以跑?我就不清楚了。現在剛好我手上又變成沒有 cygwin 機器了。搞不好 0.11 在 cygwin 上變成不能跑。
不過不管怎麼樣,這裡只是 display hook 上面的問題而已。最多就是顯示出問題。

Ubuntu 上建議使用有顯示 UTF8 能力的 Terminal。

最後,Ubuntu 上錯誤顯示會失效,因為 sys.excepthook 已經被其他 package 搶走了。我用很保守的策略來搶 excepthook,所以別人搶了,我就讓給別人。當然,你可以設定為強迫 excepthook(看程式碼)。
所以 hello.py 的錯誤展示有點多餘。

另外,還有一點小改動就是不再像 0.1 那樣 hook zhpy_codec 的 decode,只 hook streamReader。


更新(2008-03-01):
zhpy 1.5 已經出了,我雖然還沒有仔細看,不過應該有一些有趣的進展。