Lisp,這門擁有近 60 歲高齡的語言,被 Paul Graham 譽為「黑客的秘密武器」,在 MIT 教學大綱中佔據核心地位,卻始終未進入主流。Java 程序員若願跨越語法陌生感,將發現其極簡核心——一切皆列表——蘊含著超越主流語言的抽象能力與表達力。
Lisp 只有兩種基本單元:原子(數字、符號、字符串)與列表(括號包裹的序列)。列表第一個元素是操作符,其餘是參數:
> (+ 1 2 3) ; 求和 → 6
> (* 1 2 3 4) ; 求積 → 24
> (first '(lions tigers bears)) ; 取首 → LIONS
> (rest '(lions tigers bears)) ; 取尾 → (TIGERS BEARS)
> (cons 'lions '(tigers bears)) ; 構造 → (LIONS TIGERS BEARS)
'(quote)延遲求值,將列表作為數據而非代碼處理。這一機制打通了「程序」與「數據」的界限——代碼本身就是可操作的列表數據結構。
(defun my-second (lst)
(first (rest lst)))
(defun my-max (x y)
(if (> x y) x y))
defun 本身就是列表:操作符 defun,參數為函數名、參數列表、函數體列表。條件結構 (if condition then else) 同理。語法樹即源碼,這是元編程的終極基礎。
Lisp 無循環構造(早期版本),遞歸配合 first/rest 成為列表遍歷主流:
(defun total (lst)
(if (null lst)
0
(+ (first lst) (total (rest lst)))))
尾遞歸優化(TCO)將特定遞歸轉為迭代,消除棧溢出風險,使遞歸成為處理樹、圖等遞歸數據結構的首選——Java 缺乏 TCO,遞歸深度受限,常被迫改寫為迭代。
(setf total (lambda (a b) (+ a b))) ; 定義匿名函數並綁定到 total
(apply total '(101 102)) ; 應用 → 203
lambda 創建閉包,apply 將列表參數展開調用。高階函數(接受/返回函數)構建了比對象更高層的抽象:mapcar、remove-if、reduce 等將控制流抽象為可組合的函數組合子。
宏在編譯期/讀取期操作代碼列表,進行結構變換:
(defmacro times-two (x)
`(* 2 ,x)) ; 反引號 ` 模板,逗號 , 求值插值
(times-two 4) ; 宏展開為 (* 2 4) → 8
關鍵差異:函數求值參數,宏操作源碼。宏參數不預先求值,而是直接作為列表嵌入模板——這賦予了定義新控制結構、領域特定語言、消除樣板代碼的能力。Lisp 自身大部分關鍵字(defun、let、loop、setf)皆由宏構建。
雖不必轉用 Lisp,但其核心思想可移植:
Lisp 之美在於以極小的核心(列表、原子、求值規則)支撐無限的抽象塔樓。它證明了:語言不需龐大關鍵字集,只需賦予程序員「定義新語言特性」的能力。今天的主流語言正在以不同形式回歸 Lisp 的懷抱——Lambda、Stream、宏、REPL、不可變集合……跨越邊界學習 Lisp,不是為了寫 Lisp,而是為了在任何語言中都能用更高維度的抽象思維去解決問題。