你問宏展開 - 但我想澄清的功能是如何優先處理。
注重當調用和定義實際情況。在第二點中,你說功能中的代碼可以調用稍後定義的函數。這不完全正確。
在像C++聲明和定義函數,然後編譯您的應用程序語言。忽略內聯,模板,lambda表達式等神奇功效......,編譯功能時,通過該功能使用的所有其他功能的聲明需要存在 - 和鏈接時,編譯後的定義需要出現 - 所有程序之前開始運行。一旦程序開始運行,所有功能已經完全準備就緒,可以被調用。
現在Lisp中,情況就不同了。現在忽略編譯 - 讓我們來想一下解釋的環境。如果你運行:
;; time 1
(defun a() (b))
;; time 2
(defun b() 123)
;; time 3
(a)
在時間1你的程序沒有功能。
第一defun
然後創建函數(lambda() (b))
,並將其與該符號a
。此功能包含這個時間點他並沒有叫b
一個參考符號b
,但。 a
只會調用b
當a
本身被調用。
所以,在時間2你的程序有一個功能,用符號a
相關,但尚未執行。
現在第二個defun
創建一個函數(lambda() 123)
,並將它與符號b
關聯。
在時間3,您的程序有兩個功能,與符號a
和b
相關聯,但尚未被調用。
現在撥打電話a
。在執行過程中,它會查找與符號b
,相關的函數,發現此時該函數已存在於此時間點,並調用它。 b
執行並返回123.
讓我們添加更多代碼: ;;時間4 defun b()456) ;;時間5 的(a)
時間4之後,一個新的defun
創建函數返回456,並將其與該符號相關聯b
。這取代了引用b
,它保留了返回123的函數,然後垃圾回收(或任何你實現的東西去除垃圾)。
調用a
(或者更準確地說,用符號a
的功能屬性引用的拉姆達),現在將導致對相反,如果我們最初寫了返回456
調用一個函數:
;; time 1
(defun a() (b))
;; time 2
(a)
;; time 3
(defun b() 123)
...這將不工作過,因爲時間2後,當我們稱之爲a
,它無法找到與符號b
相關的功能,所以它會失敗。
現在 - compile
,eval-when
,優化等魔法可以做各種從我上述不同的時髦的事情,但要確保你擔心的是更先進的東西之前,首先有這些基本的把握。
- 功能僅在該
defun
被調用的時候創建的。 (解釋器不會「向前看文件」。)
- 符號的一個屬性是對函數的引用。 (函數本身實際上並沒有名稱。)
- 多個符號可以引用相同的函數。 (
(setf (symbol-function 'd) (symbol-function 'b))
)
- 定義函數
a
調用函數b
(通俗的說),只要符號b
具有由時間a
相關功能被稱爲是OK。 (在defun
ning a
時不需要)
- 符號可以指不同的功能在不同的時間。這會影響「調用」該符號的任何函數。
的宏的規則不同(其擴展是「讀」的時間後靜態),但許多原則保持不變(找他們Lisp的不「的文件中展望」) 。理解Lisp程序比你可能習慣的大多數(較少;-))語言更具動態性和「運行時間」。瞭解什麼發生當在執行Lisp程序期間,管理宏擴展的規則將開始有意義。
http://clhs.lisp.se/Body/03_abab.htm –
有關宏的詳細處理,請參閱:http://www.paulgraham.com/onlisp.html 您可以從那裏下載該書。 –