為什麼Haskell不需要Macro
來自專欄馬索萌帶你玩轉編程5 人贊了文章
最近出於興趣開始學習Haskell,一個我很好奇的地方在於Haskell沒有Macro怎麼實現擴展語法,因為我會不由自主地拿Lisp最Mind Blowing的特性跟同樣出色的語言對比。這裡討論的Macro是Lisp裡面自己可以生成代碼的Macro,不是文字替換那種Macro,而Lisp的Macro是我見過最強大的元編程系統 (meta-programming) ,它能夠讓你自己生造語法。
結果是Haskell給了我驚喜。Lisp雖然用的人不多,但它的思想被各類火爆的編程語言都借鑒過去了,以至於我在學完common lisp之後再學習新的語言很少感到Mind Blowing,因為這些語言的思想都已經在Lisp裡面出現過了,直到我學習了Haskell。
Haskell再次讓我感到耳目一新。很多年前我在學習Lisp之前看過Haskell的介紹(那時候我剛開始學習編程沒多久),其中有一條很自豪的lazy evaluation。當時我並不理解這個特性有什麼意義,甚至覺得多此一舉。現在當我思考Haskell的元編程能力的時候我突然恍然大悟,lazy evaluation不就可以讓函數來實現macro的功能嗎。
讓我們看個簡單的例子,在Lisp中假設我們要創造一個叫做doif的語法(只是為了舉個簡單例子,if已經有這個功能),用法如下
(doif x y)
當x為真的時候執行y,否則什麼也不幹。重點在於不一定要evaluate y的值,僅當x為真的時候才需要evaluate y。在Lisp中我們需要Macro而不能用函數來定義doif
(defmacro doif (x y) `(if ,x ,y)) ;; 正確寫法(defun doif (x y) (if x y)) ;; 錯誤寫法,會先evaluate y
而在Haskell中,我們只需要像定義普通函數那樣定義doif就可以了,如下
doif x y = if x then y else ()
由於lazy evaluation,doif僅在需要的時候evaluate y,也就是x為真的時候。所以,我們僅僅使用普通的函數定義就產生了新的語法,而且這個寫法比defmacro簡潔,這確實是Haskell神奇的地方。
誠然,在某些情況下lazy evaluation不能實現所有defmacro所能實現的,但是macro主要的目的是為了簡化、重用code,這點Haskell已經做的夠好了,而且Haskell並不需要為DSL再發明一個類似macro的系統,而是自然而然使用語言內置的功能,這一點的體驗比defmacro好很多,因為寫macro真是一件頭疼的事情,複雜的Macro能把人繞的暈頭轉向,尤其是碰到嵌套`的時候(雖然寫完之後用的很爽)。
更複雜的例子等我更加精通Haskell再寫吧。
推薦閱讀:
※學 Haskell 果然是要趁早
※喬波今天學了點定理證明
※初窺Haskell:解析一個數學表達式
※如何看待 Facebook 有超過一百萬行 Haskell 代碼?
※Agda 中的 coinductive data type