为什么Clojure不支持宏中的私有函数?(Why does not Clojure support private functions in macro?)

编程入门 行业动态 更新时间:2024-10-25 16:23:00
为什么Clojure不支持宏中的私有函数?(Why does not Clojure support private functions in macro?)

我试图实现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 public

Problem 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.

更多推荐

本文发布于:2023-08-07 05:03:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1460038.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:不支持   函数   Clojure   support   macro

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!