我试图实现xor宏并想出了一个问题。
我无法在宏中使用私有函数。
这是一个例子:
私人功能
(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 next)] (if (= (count '~next) 1) (xor-result first# second#) (xor (xor-result first# second#) ~@(rest next))))))这是错误 :
CompilerException java.lang.IllegalStateException: var: #'kezban.core/xor-result is not public当我删除^:private flag时问题解决了 。
问题是: 这种行为的原因是什么?
更新 :我可以使用以下方法的 私有函数 。
私人功能
(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 '(~@next)) result (xor-result (eval first) (eval second))] `(if (= (count '~next) 1) ~result (xor ~result ~@(rest next))))))I was trying to implement xor macro and came up with a problem.
I couldn't use private function in a macro.
Here is the example:
private function
(defn :^private xor-result [x y] (if (and x y) false (or x y)))macro
(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#) ~@(rest next))))))Here is the Error:
CompilerException java.lang.IllegalStateException: var: #'kezban.core/xor-result is not publicProblem solves when I remove ^:private flag.
Question is: What is the reason of this behaviour?
UPDATE: I can use private function with the following approach.
private function
(defn ^:private xor-result [x y] (if (and x y) false (or x y)))new macro
(defmacro xor ([] true) ([x] x) ([x & next] (let [first x second `(first '(~@next)) result (xor-result (eval first) (eval second))] `(if (= (count '~next) 1) ~result (xor ~result ~@(rest next))))))最满意答案
如果在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函数,而是使用表示代码的数据调用xor-result函数。 在编译期间直接在宏中调用xor-result 。 在宏的第一个版本中,它在宏生成的代码中使用,在编译期间不会被调用。
If you have a macro in ns1:
(ns ns1) (defn- my-fun [x] (first x)) (defmacro my-macro [x] (my-fun ~x))And use it in another namespace:
(ns ns2 (:require [ns1 :refer [my-macro]])) (my-macro [1 2])The compiler will call the macro during compilation phase and it will generate code in ns2 namespace and will become:
(ns ns2 (:require [ns1 :refer [my-macro]])) (ns1/my-fun [1 2])and this code will be eventually compiled to byte code.
As you can see the compiler will see usage of a ns1's private function in ns2 namespace and will complain about it.
To debug your macros you can use macroexpand to see the result of applying your macro.
You also need to remember that your macros work on your program data: datastructures representing your code (symbols, lists, vectors etc.). For example in your second version of the macro it works symbols as they are, not runtime values bound to them:
(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))As you can see your xor-result function won't be called with the actual runtime values but rather with the data representing your code. xor-result is called in your macro directly during compile time. In the first version of your macro it is used inside of the code generated by the macro and is not called during compilation.
更多推荐
发布评论