Literate Programming
Let us change our traditional attitude to the construction of programs: Instead of imagining that our main task is to instruct a computer what to do, let us concentrate rather on explaining to human beings what we want a computer to do.
-- Donald Knuth. "Literate Programming (1984)"
Thinker 的一篇心靈與程式碼的協奏曲提到程式由後往前寫似乎比較符合思考的方向,不禁讓我想到 Knuth 提出的 Literate Programming 方法;其實我們思考的順序有時是跳躍式的,用 LP 的方法可以完全跳脫先後關係,用自己喜歡的順序來寫,我覺得也可以稱為碎碎唸寫法。
用 Thinker 的同一個例子,改作 noweb 的格式,用 LP 的方法來寫,會變成怎樣?首先定義問題:
假設問題是,function 接受一字串,裡面的每一行有兩個欄位,皆是整數。欄 位以一個空白相隔。function 必把每一行的兩個欄位的數字相乘,然後再將每 一行的結果加總。
我們需要一個接受一個字串的 function :
<<接受字串的 function>>= def mul_n_sum(data): <<function 內容>> @
這個 function 必須把每一行的兩欄數字相乘,然後相加;假設我們取得每一行的兩個數字之後照順序存放在 field_lines 這個變數裡面,則用 sum 就可以把兩兩相乘之後的數字加總:
<<function 內容>>= <<取得每一行的兩個數字>> return sum([field1 * field2 for field1, field2 in field_lines]) @
要怎麼取得每一行的兩個數字呢?首先要把每一行的字串切開:
<<取得每一行的兩個數字>>= lines = data.strip().split('\n') @
然後被切開的每一行字串經過分割後,會變成依照
[field1, field2], [field1, field2], [field1, field2], ...
順序排列的字串,所以我們還要轉換成數字才能運算:
<<取得每一行的兩個數字>>= <<分割欄位>> field_lines = [[int(field1), int(field2)] for field1, field2 in txt_field_lines] @
最後,分割欄位有很多方法,因為我們已經知道輸入的格式不會錯誤,所以用簡單的 str.split() 來切割就可以了:
<<分割欄位>>= txt_field_lines = [line.split() for line in lines] @
這篇 blog 經過 notangle 的處理,會變成以下的 python 程式:
# notangle -R'接受字串的 function' literate-programming.mdwn def mul_n_sum(data): lines = data.strip().split('\n') txt_field_lines = [line.split() for line in lines] field_lines = [[int(field1), int(field2)] for field1, field2 in txt_field_lines] return sum([field1 * field2 for field1, field2 in field_lines])
可以跟 Thinker 的結果比比看 :)
這篇是故意使用類似的思考邏輯來寫,所以會產生相似的程式,且為了展示 LP 我最後還刻意調整了一下順序。只要換一下思考的方向,要寫出 loop 的版本也是有可能的。重點在於隨想隨寫,邊寫程式邊紀錄思考過程。
碎碎唸的好處是不怕跳躍式的思考,想寫什麼就寫什麼,邊想邊寫,壞處是最後組合出來的程式一般人可能沒辦法直接看懂,但是這樣寫還真的滿有趣的,有機會一定要試試!
其他參考資料:
Comments