2016-09-23 63 views
4

我試圖實施宏或宏,並想出了一個問題。爲什麼Clojure不支持宏中的私有函數?

我無法在宏中使用私有函數。

這裏是例如:

私有函數

(defmacro xor 
    ([] true) 
    ([x] x) 
    ([x & next] 
    `(let [first# ~x 
      second# ~(first next)] 
     (if (= (count '~next) 1) 
     (xor-result first# second#) 
     (xor (xor-result first# second#) [email protected](rest next)))))) 

這裏是錯誤

CompilerException java.lang.IllegalStateException: var: #'kezban.core/xor-result is not public 

問題解決當我刪除^:私人標誌。

問題是:這種行爲的原因是什麼?


更新:我可以用私有函數具有以下方法

私有函數

(defn ^:private xor-result 
    [x y] 
    (if (and x y) 
    false 
    (or x y))) 

新宏

(defmacro xor 
    ([] true) 
    ([x] x) 
    ([x & next] 
    (let [first x 
     second `(first '([email protected])) 
     result (xor-result (eval first) (eval second))] 
    `(if (= (count '~next) 1) 
     ~result 
     (xor ~result [email protected](rest next)))))) 

回答

5

如果你有ns1宏:

(ns ns1) 

(defn- my-fun [x] (first x)) 

(defmacro my-macro [x] (my-fun ~x)) 

並使用它在另一個命名空間:

(ns ns2 
    (:require [ns1 :refer [my-macro]])) 

(my-macro [1 2]) 

編譯器將在編譯階段調用宏,它會在ns2命名空間生成的代碼將成爲:

(ns ns2 
    (:require [ns1 :refer [my-macro]])) 

(ns1/my-fun [1 2]) 

這個代碼最終會被編譯成字節碼。

正如你所看到的,編譯器會在ns2命名空間中看到ns1的私有函數的用法,並且會抱怨它。

要調試您的宏,您可以使用macroexpand來查看應用宏的結果。

您還需要記住,您的宏對您的程序數據有效:代表您的代碼的數據結構(符號,列表,向量等)。例如,在您的宏的第二個版本,它的作品的符號,因爲它們不運行時綁定到這些值:

(macroexpand '(xor true false)) 
;; => (if (clojure.core/= (clojure.core/count (quote (false))) 1) true (boot.user/xor true)) 

(macroexpand '(xor (zero? 1) (zero? 0))) 
;; => (if (clojure.core/= (clojure.core/count (quote ((zero? 0)))) 1) false (boot.user/xor false)) 

正如你可以看到你的xor-result功能將與實際運行時的值,而是與被稱爲代表您的代碼的數據。在編譯期間直接調用xor-result。在宏的第一個版本中,它被用在由宏生成的代碼中,並且在編譯期間不會被調用。

+0

[ns1:refer [xor]]在此代碼示例中。 xor是指什麼? –

+0

啊,錯字,固定。 –

+0

我添加了使用私人功能的新方法。你能解釋這種行爲嗎? –

相關問題