- 讀 clojure 的線上書籍、文件,寫語言的特性、語言的觀念 ---重點關注在 clojure 的文章。
- 寫一些不痛不癢的小習題。 4clojure.com 有 150 多題的練習題。
- 讀一些和 clojure 相關、又不直接談 clojure 的文章。比方說「教 Lisp 的文章」「Lisp 的歷史」「Rich Hickey 的一些 slide 」
後來研究了所謂的 language oriented programming, bottom-up approach 等等應用 macro 來做 meta-programming 的高級應用技巧。 當我和朋友聊這個的時候,朋友給了一個回應:「嗯,也許 Lisp 語言真的是最適合做 meta-programming 的語言,但是你上一回寫 meta-programming 是什麼時候?」
於是,我心裡的大哉問就變成了:「對於自身不太使用 meta-programming 技巧的程式設計師,clojure 語言是否依然可以帶來生產力的提昇?」會問這個問題是因為之前有看過一篇文章講為什麼「函數式編程」可以提高程式設計師的生產力,文章中所論述最重要的理由,因為「高階函數」與「惰性求值」這兩項特性可以提高程式碼模塊化的程度。函數式編程的特性,現在許多的語言都加入了,那 clojure 如果不討論 meta-programming 的話,它的表達能力 (expressiveness) 還會比一些更主流的語言 python, Ruby 等也有函數編程特性的語言來得更強嗎?
那我們來看一段程式碼吧: flatten 函數,可以用來「壓平」樹狀資料結構。
例如:
接下來,有趣的事就是,如果我們去看 flatten 的 source code 。
啥! flatten 居然是用 tree-seq 來定義的!為了這件事,我還多看了一下,clojure 哪些內建的函數也是用 tree-seq 來定義? 結果 file-seq 和 xml-seq 也都是用 tree-seq 來定義。而 tree-seq 是一個高階函數,接受三個參數:一個是用來接收「定義分支的函數」、一個是用來接收「展開分支子樹的函數」,一個是用來接收「樹資料結構」。
「樹」這樣子的資料結構、對應的「走訪方式」,例如: tree-seq。在其它的語言,往往沒有「極簡」的實現。像 python 的話,自然也會有「樹」相關的走訪函式庫、「樹」的資料結構實現。卻比較多是物件導向式的、或是每一家發展不同風格的作法。這一類的問題:標準函式庫較為一致、外部函式庫較不一致的問題,我認為是語言表達能力受限制的主因之一。
要深入討論語言表現能力的話,我認為這關系到程式語言設計的一致性 (consistency)。以 python 為例, python 在函數式編程領域,後期發展的語法傾向是用 list comprehension 來取代 filter, map, reduce 之類的函數。這個很自然,因為用 list comprehension 的表現能力更強,寫 python 的使用者可以在記憶最少的語法的前提之下,得到最大的表達能力。
於是這就回到了一個很有趣的議題,程式語言的設計,其實必須考慮人類認知能力的限制。以 C++ 語言為例,C 的語法、語件導向的語法、template 的語法,三種語法都大不相同。tempalte 尤其複雜。複雜的語法導致了使用者學習時難學、使用者上手之後也難用,因為語法冗長。而 Lisp 的括號語法,最初來自於偷懶,因為 Lisp 的作者還沒有為它設計合適的語法,所以就先用語法樹 (syntax tree) 來湊合著用,卻因此讓 Lisp 語言成為了有最簡單 (simple) 語法的語言,同時也是語法最一致 (consistent)的語言,進而可以讓使用者寫出簡潔 (concise) 的程式。
那我們來看一段程式碼吧: flatten 函數,可以用來「壓平」樹狀資料結構。
例如:
> (flatten [1 2 [3 [4 5] 6]])
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; clojure.core/flatten from | |
;; http://clojuredocs.org/clojure_core/clojure.core/flatten | |
;; Copyright Rich Hickey | |
(defn flatten | |
"Takes any nested combination of sequential things (lists, vectors, | |
etc.) and returns their contents as a single, flat sequence. | |
(flatten nil) returns nil." | |
{:added "1.2" | |
:static true} | |
[x] | |
(filter (complement sequential?) | |
(rest (tree-seq sequential? seq x)))) |
「樹」這樣子的資料結構、對應的「走訪方式」,例如: tree-seq。在其它的語言,往往沒有「極簡」的實現。像 python 的話,自然也會有「樹」相關的走訪函式庫、「樹」的資料結構實現。卻比較多是物件導向式的、或是每一家發展不同風格的作法。這一類的問題:標準函式庫較為一致、外部函式庫較不一致的問題,我認為是語言表達能力受限制的主因之一。
要深入討論語言表現能力的話,我認為這關系到程式語言設計的一致性 (consistency)。以 python 為例, python 在函數式編程領域,後期發展的語法傾向是用 list comprehension 來取代 filter, map, reduce 之類的函數。這個很自然,因為用 list comprehension 的表現能力更強,寫 python 的使用者可以在記憶最少的語法的前提之下,得到最大的表達能力。
於是這就回到了一個很有趣的議題,程式語言的設計,其實必須考慮人類認知能力的限制。以 C++ 語言為例,C 的語法、語件導向的語法、template 的語法,三種語法都大不相同。tempalte 尤其複雜。複雜的語法導致了使用者學習時難學、使用者上手之後也難用,因為語法冗長。而 Lisp 的括號語法,最初來自於偷懶,因為 Lisp 的作者還沒有為它設計合適的語法,所以就先用語法樹 (syntax tree) 來湊合著用,卻因此讓 Lisp 語言成為了有最簡單 (simple) 語法的語言,同時也是語法最一致 (consistent)的語言,進而可以讓使用者寫出簡潔 (concise) 的程式。