Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 使用前向声明的宏时参数数错误_Clojure - Fatal编程技术网

Clojure 使用前向声明的宏时参数数错误

Clojure 使用前向声明的宏时参数数错误,clojure,Clojure,我在宏中有一个函数my plus,它包含一个名为my macro的宏。但是我的宏是在我的plus宏定义之后声明的。我使用声明以避免无法解决符号错误 我在repl中键入这些代码 (declare my-macro my-plus) (defn my-plus-in-macro [x y] (my-macro (my-plus x y))) (defmacro my-macro [my-fn] `~my-fn) (defn my-plus [x y] (+ x y)

我在宏中有一个函数my plus,它包含一个名为my macro的宏。但是我的宏是在我的plus宏定义之后声明的。我使用声明以避免无法解决符号错误

我在repl中键入这些代码

(declare my-macro my-plus)


(defn my-plus-in-macro [x y]
    (my-macro (my-plus x y)))


(defmacro my-macro [my-fn]
    `~my-fn)


(defn my-plus [x y]
   (+ x y))
然后,如果执行这个,我希望得到3

(my-plus-in-macro 1 2)
但是我得到的是

ArityException Wrong number of args (1) passed to: user$my-macro  clojure.lang.AFn.throwArity (AFn.java:437)
但是,如果我在repl中再次在宏定义中执行这个加号

(defn my-plus-in-macro [x y]
    (my-macro (my-plus x y)))
然后我执行这个 (我在宏1和宏2中的加号)

正是我所期望的,3

在我第一次执行(宏1 2中的加号)时发生了什么

不知何故,当我第一次在宏中定义加号时,clojure看到了我的宏符号,但它还不知道我打算将其用作宏的名称

虽然在宏中定义加号之后,我就将宏定义为符号,但clojure仍然不知道我的宏是宏的符号。这就是为什么我有算术例外

但是,不知何故,当我用相同的代码重新定义我的plus in宏时,Clojure现在知道我的宏是一个宏,并将其视为一个宏,然后我的代码就可以工作了

当然,如果我在宏定义中将宏定义放在加号之前,我不会得到任何异常。但这是否意味着我不能使用declare为宏保留符号

编辑

根据@xsc的回答,这些代码是有效的。 我只需要通过提供:form和:env以“正确”的方式在宏定义中调用plus中的宏

(declare my-macro my-plus)


(defn my-plus-in-macro [x y]
    (my-macro :form :env (my-plus x y)))


(defmacro my-macro [my-fn]
    `~my-fn)


(defn my-plus [x y]
   (+ x y))


(my-plus-in-macro 1 2)
3
编辑-0

@xsc您是对的,我不能使用声明转发宏的声明符号。我必须把宏定义放在任何使用它的函数之前

所以,这是正确的代码

(declare my-plus)

(defmacro my-macro [my-fn]
    `~my-fn)

(defn my-plus-in-macro [x y]
    (my-macro (my-plus x y)))

(defn my-plus [x y]
   (+ x y))

(my-plus-in-macro 1 2)
3

宏是在编译时计算的,这意味着编译器/读取器必须知道哪些符号表示宏,哪些符号不表示宏。通过简单地使用
declare
,您并没有提供这些信息,这意味着您将在代码中引用宏函数,而不是将宏调用替换为其计算值

换句话说:当读者第一次遇到
my macro
时,除了把它放在那里,没有什么比这更好的了。因为任何宏都只是一个函数(将
:macro
元数据设置为
true
),所以在下面进一步定义后,这不会造成问题

通过以“正确”的方式调用宏函数,提供通常隐式传递的
&form
&env
参数,可以检查这一事实:

(declare my-macro)

(defn my-function
  [x]
  (my-macro :form :env x))

(defmacro my-macro
  [x]
  (vector &form &env x))

(my-function (+ 1 2)) ;; => [:form :env 3]
请注意,表单
(+12)
在传递给“宏”之前进行计算,因为我们在这里处理的是一个普通的旧函数

您可以使用前面提到的
:macro
元数据将符号声明为宏,但这只会在首次调用时导致异常,因为实际调用是在var绑定到任何对象之前:

(declare ^:macro my-macro)

(defn my-function
  [x]
  (my-macro x))
;; => IllegalStateException: Attempting to call unbound fn: #'user/my-macro ...

TL;DR:声明宏将不起作用,因为它在读卡器/编译器遇到宏时即被调用,无论它嵌套在函数中有多深。

哇!您如何知道宏需要提供:form和:env?有什么阅读建议吗?太糟糕了,官方声明文档中没有关于宏的警告[请注意,
&form
通常包含原始宏调用和执行调用的环境,而不是我上面提供的两个关键字。IIRC,这两个特殊符号在我的第一本Clojure书中提到。我猜它卡住了。:)在编辑中:这不“起作用”从这个意义上说,宏现在正在工作。您只是正确地调用了底层函数,但这意味着使用宏毫无意义。正如我所说的,您不能向前声明宏。