2013年8月30日 星期五

以下為摘錄

追求神乎其技的程式設計之道(七)
http://blog.vgod.tw/2008/10/10/divine-code-7/

獨立思考抽象化定義問題以及解決問題的能力
獨立思考,找到問題的根本,進而清楚定義問題,但最終你還是要解決問題才算是達到圓滿


優秀程式設計師
第一要件:「熱情」
第二要件:「思考」,特別是抽象化的思考能力

寫程式需要的思考能力第一是邏輯思考,主要其實就是用正確、清晰的邏輯表達想法而已,說來簡單但要做好也是需要一定時間的訓練。第二是抽象化思考

我覺得所有的程式都可以看成一個巨大的金字塔,頂端是這個程式的最終目標,一個模糊的概念;底部是細節的程式碼。而中間是一個經由不斷切割與抽象化所構成的高塔,每一個程式都是切割為許多的元件、模組,再切為更細的class和function,再來是最底下的變數與邏輯判斷式。


程式語言就是決定思考高度的一個關鍵因素,而這也間接決定了寫程式的能力。
舉一個簡單的例子,高階的script語言幾乎都內建map這個資料結構。(也就是一對一的對應表,給它一個key,就能很快的找到其對應的value。有的語言稱為dictionary、hash、或associative array。)如果寫習慣Python或Ruby的人,一定會很直覺的用map來儲存任何對應關係,甚至用來表示會動態變更欄位的struct。但是,在C語言裡沒有這種東西,這讓很多只會寫C的人直覺的用陣列加上linear search來存放這種對應關係。如果資料結構學得好的人,會知道這樣寫效率很差,但很多時候因為沒有方便的library,也懶得自己寫一個高效率的map(不過是存一個電話簿,我難道要先寫一個紅黑樹嗎?),就妥協於沒效率的儲存方法。
這就是一個被程式語言限制住的典型例子。在高階語言用map存東西實在太容易了,所以這會變成思考時的一個小單位,跟人溝通或是規劃架構時都能隨時拿來用。但相反地,在低階語言裡,要有效率又簡單的儲存這種對應關係實在很麻煩,所以人們在思考時會傾向選擇容易的方法來做,而自然忽略掉了以map為基礎的解決方法。



除了script language外,functional language也是另一個進化到神乎其技路上必備的技能。functional language是以function為基礎來思考的程式語言,典型的代表是LISP、Scheme、Haskell。(這邊所說的function是higher order function,可以以其他function為參數的function,和C語言裡的function是不同的概念。)在functional的世界最棒的特性是程式可以只靠function間的相互組合而生成,不用迴圈不用if一樣可以達成同樣的目的。
舉例來說,如果我要要從一個電話簿中挑出所有姓張的人,並傳回他們的電話,用低階語言(其實我指的是imperative language,但這裡就不要這麼講究了)寫起來大概是這樣:
  1. PhoneData contacts[N] = {…..};
  2. String number[MAX_NUMBERS];
  3. int count = 0;  
  4. for(int i = 0; i < N; i++){
  5.   if( !strncmp( contacts[i].name"張"1 ) ) // well, 讓我們假設這個strncmp支援unicode
  6.     ret[count++] = contacts[i].number;
  7. }
  8. return ret;
用低階語言寫程式必須不斷處理瑣碎的細節,像是要開多大的陣列、要弄一個額外的counting變數、要用迴圈一個個檢查陣列….。當腦袋裡充滿這些細節時,是很難切換到更高的角度思考的。而functional language提供完全不同的思考方式來解決同樣的問題,以下我用Ruby的語法寫同樣的程式(Ruby具備許多functional language的特性,但不全然是個functional language):
  1. contacts = [ { 'name' => '...''number' => '...' }, ... ]
  2. return contacts.find_all{ |c| c['name'][0,1] == '張' }.map{ |c| c['number']}
是的,你沒看錯,就只有兩行,而且真正做事的只有一行而已。這裡用到的是functional language的基本工具:filter(Ruby裡叫find_all)和map。這兩個function特別的地方在於他們能用來取代一般需要迴圈才能做的事,並賦予除了「迴圈」以外更高階的抽象意義。filter的意思是過濾,可以從一個陣列中用一個給定的function為條件來去除不合條件的元素;而map的意義是對應和轉換,可以用一個給定的function作為規則把一個陣列中的每個元素全轉換成另一個樣子。
多了這一層抽象化後,寫程式的思考方式會變得完全不同。迴圈不再只是迴圈,而是可以根據它的目的將之區分為map或filter(其實還有更多,這邊只是先舉兩個做例子),思考時便能以組合這些小元件的方式來構思程式的寫法。這裡提供的不只是語法上的簡便而已,而是整個思維的大躍進,以及思考高度的提昇。



參考:
追求神乎其技的程式設計之道(七)
http://blog.vgod.tw/2008/10/10/divine-code-7/

http://mmdays.com/2007/02/26/learning/

沒有留言:

張貼留言