2010-02-25 61 views
6

假設我有一堆命名空間(蘋果,香蕉,桔子)。在這些命名空間中,我使用調用eat宏,該宏調用(不是「生成」,調用peel函數。每個水果的peel函數是不同的,但宏是相同的,並且相當大,所以我想要創建一個包含eat宏的名稱空間fruit。但是當我從apple名稱空間調用eat宏時,eat宏應該調用apple/peel函數。關於clojure命名空間和宏的問題

爲了說明(但不工作):

(ns fruit) 
(defmacro eat [] (peel)) 

(ns apple) 
(defn peel [] (prn "peeled apple")) 
(fruit/eat) 

(ns banana) 
(defn peel [] (prn "peeled banana")) 
(fruit/eat) 

要強調的是,這意味着剝離功能應時,稱爲且僅當宏被擴展爲在本例子。

(ns apple) 
(defn peel [] (prn "peeled apple")) 
(defmacro eat [] (peel)) 
(macroexpand-1 '(eat)) 

那麼,關於如何結合宏和多態的任何想法?

回答

1

編輯:對不起。我已經發布了以下內容。但是你說「打電話,不生成」剝離功能。所以我寫的可能不是你想要的,雖然它看起來會得到預期的結果。

簡單引用(peel)爲我工作。

(ns fruit) 
(defmacro eat [] '(peel)) 

(ns apple) 
(defn peel [] (prn "peeled apple")) 
(fruit/eat) 

(ns banana) 
(defn peel [] (prn "peeled banana")) 
(fruit/eat) 
+0

謝謝,但事實上並非我的意思。它在這裏得到了期望的結果,但不是在我的實際使用情況中。 – 2010-03-02 15:17:55

2
(defmacro eat [] ((var-get (resolve 'peel)))) 

請注意,您在濫用命名空間,雖然。

7

你所描述的不是多態,而是所謂的本地捕獲。你想吃宏宏來「捕獲」本地定義果皮

在大多數Lisp中,這被認爲是不好的風格,尤其是Clojure,因爲它會導致細微和不可預知的錯誤。

更好的解決方案是通過正確的剝離宏,當你把它叫做:

(ns fruit) 
(defmacro eat [peeler] `(~peeler)) 

(ns apple) 
(defn peel [] (prn "Peeled an apple")) 
(fruit/eat peel) 

如果你真的想這樣做本地捕獲,您可以用〜」迫使它(引文結束引號)宏:

(ns fruit) 
(defmacro eat [] `(~'peel)) 
+0

這不完全是我的意思。我希望在展開時間內調用'peel'函數。我澄清了這個問題。 – 2010-03-02 15:15:46

+0

我明白了,會提供另一個答案。 – 2010-03-05 01:24:38

3

作爲編輯的問題解釋說,這是當地捕獲略有不同,因爲你不使用剝離在宏展開中,而是在宏本身的執行中。

這很困難,因爲宏不評估它們的參數。即使你通過果皮作爲參數,在宏體內它只是一個符號,而不是一個可調用的函數。

做你想要什麼(不使用EVAL)的唯一途徑是解決在編譯時符號:

(defmacro eat [] 
    ((var-get (resolve 'peel))) 
    ... return the expansion of "eat" ...) 

決心功能需要一個符號,並返回它映射瓦爾到當前的命名空間。獲得Var後,可以用var-get檢索實際功能(Var的值)。額外的一組圓括號稱這個函數。

不用說,這是一個非常不尋常的設計,可能需要重新考慮。