2014-11-03 76 views
4

在這裏,我的一般焦點是Scala和Lisp/Scheme宏,不完全是在C/C++/Obj-C中的那些我只是看不到這一點。宏的目的是什麼?

我理解它的方式是,宏有擴展語言。但功能也是如此。

我知道有些東西由於某些語言的限制而不能幹淨地實現,因此需要一個宏來實現。但是我用宏看到的很多例子似乎都是使用普通函數很容易實現的東西。

那究竟是什麼目的呢?清理宏或以其他方式,有人請賜教。如果可能的話,請提供一些可以在宏中完成的示例代碼,但對於普通函數來說是不可能的/難以做到的。

+0

http://stackoverflow.com/questions/267862/what-makes -lisp-macros-so-special?s = 6 | 1.8097 http://stackoverflow.com/questions/5833033/in-lisp-code-is-data-what-benefit-does-that-provide/5833388?s = 11 | 1.6415#5833388 – 2014-11-04 11:05:30

+0

http://stackoverflow.c的副本om/questions/2561221/examples-of-what-lisps-macros-can-be-used-for?s = 7 | 4.5505 – 2014-11-04 11:07:00

回答

7

對Scala宏所做的事情有一個簡明的總結:http://scalamacros.org/paperstalks/2014-02-04-WhatAreMacrosGoodFor.pdf。綜上所述,已知宏可用於:1)代碼生成,2)高級靜態檢查,3)授權特定於領域的語言。 Scala中的宏是基於類型的,爲類似Lisp的語言中的宏提供了一個額外的強大的功能。

上面鏈接的幻燈片中的一些示例確實可以在沒有宏的情況下實現,但結果或者缺乏某種意義(例如性能)或對用戶過於複雜(例如因爲重量級錯誤消息)。例如,Akka的輸入渠道可以用純粹的含義來實現,但編譯速度和可理解性會受到影響。或者,scala/async可以作爲一個編譯器插件來實現,但是它將不得不依賴於內部編譯器API,並且將更難以分發。

當然,宏不是銀彈。當用戶不是最佳選擇時,顯然存在用例,這在http://scalamacros.org/paperstalks/2014-03-01-MacrosVsTypes.pdf中概述。然而好奇的是,在許多情況下,既不是純宏觀的,也不是宏觀的解決方案,而是精心構建的混合動力車最終成爲最好的。

+0

我已編輯問題 – 2014-11-04 10:08:57

+0

第一個演示文稿中有幾個示例。我不認爲1,2,5,7和8在沒有宏的情況下是可以實現的。 3和4可以通過高級的類型編程來完成,但是編譯時和運行時的結果會比較慢,而且更難維護。 6可以近似,但用戶體驗會受到影響(錯誤消息,詞彙不一致)。 – 2014-11-04 11:42:37

2

在Common Lisp和Scheme中,大部分特殊語法的確實現了其他特殊語法,即宏。

例如,Scheme和CL都有if,condcase,但只有if是原語句法。

標準定義的宏和你自己制定的宏沒有什麼特別之處。他們的行爲和工作可以與原始人一樣好。

宏含有使讀者模糊和令人驚訝的代價。使用常見的命名約定,如with-*可能會有所幫助,但如果一個函數/過程可以完成這項工作,或者只能在少數幾個地方使用該表單,則永遠不應該使用宏。

+0

我編輯了問題 – 2014-11-04 10:09:48

1

有一些宏用於Lisp的(不知道斯卡拉)三個主要目的:

  • 定義:什麼是創建並在適當的地方直接登記。示例:defun,defgeneric,defclass(來自標準),deftable(來自後現代)。
  • Unwind-protect包裝:臨時修改狀態並確保在完成任務後修改狀態。重複編寫可能會很麻煩,所以我們創建一個簡寫。例如:with-open-file(標準),with-transaction(許多數據庫庫)。其他語言的生成:例如,CL-WHO(HTML),Parenscript(JavaScript)。通過在Lisp表單中生成其他語言的代碼,我們可以使用其他語言的宏,即使它們本身不支持。

具體的例子:爪哇7引入的簡寫,以確保在try -blocks的Closable S上的閉合:

try (SomeClosable foo = openFoo()) { 
    foo.doSomething(); 
} 

其可以在Java 6僅被表示大致是這樣的:

SomeClosable foo; 
try { 
    foo = openFoo(); 
    foo.doSomething(); 
} finally { 
    if (foo != null && foo.isOpen()) { 
     foo.close(); 
    } 
} 

Java開發人員不得不等待語言設計者實現此功能。 Lisp的開發者使用一個小宏:

(defmacro with-open-foo ((var &rest options) &body body) 
    `(let ((,var (open-foo ,@options))) 
    (unwind-protect 
     (progn ,@body) 
     (when ,var (close ,var))))) 

這樣他就可以寫

(with-open-foo (f :bar baz) 
    (do-some-foo f) 
    (and-something-else)) 

,而不是

(let ((f (open-foo :bar baz))) 
    (unwind-protect 
     (progn 
     (do-some-foo f) 
     (and-something-else)) 
    (when f (close f)))) 
+0

我編輯了問題 – 2014-11-04 10:10:24

+0

@ElectricCoffee:我編輯了答案。 – Svante 2014-11-04 10:38:31

+0

難道你不能只用'defun'作爲函數來寫-open-foo嗎? – 2014-11-04 10:48:04