我想要一个宏来定义返回它们被调用的形式的函数,例如(func 1 (a b))
返回 (func 1 (a b))
。我还想允许对这些函数进行输入验证,以确保我不会引入任何错误。 (这些表单稍后将被评估,但该代码尚未编写。)
不过,我不断收到此错误。
(defmacro defecho
"Echo function call after asserting a few things about the input"
([f] `(defecho ~f nil nil))
([f assertions] `(defecho ~f assertions nil))
([f assertions assert-failed-message]
`(defn ~f [& body] ; define a function
~(when-not (nil? assertions) ; if given a function for input validation
`(assert (~assertions body) ; define the function to assert this as true
~assert-failed-message)) ; with a given error message
(conj body (quote ~f))))) ; return the (f ~@body) list
(defecho my-test
#(< 2 (count %))
"Must be greater than zero")
-
Unhandled clojure.lang.Compiler$CompilerException Error compiling: /private/var/...228.clj:1:1 Can't use qualified name as parameter: my-test/body
-
Caused by java.lang.RuntimeException Can't use qualified name as parameter: my-test/body
最佳答案
不能使用限定符号作为函数参数。观察一下
`body
计算结果为current-namespace/body
在语法引用中,您始终可以取消引用非语法引用以获得不合格的符号:
`~'body
评估body
。 (请注意,此处取消引用用于评估内部引用本身)。
但是,在这种情况下,您应该生成一个符号,因为如果用户在 e 中使用符号 body
。 g assert-failed-message
的代码,您不希望他的 body
绑定(bind)与您的绑定(bind)重叠(请注意,当生成的函数实际执行时,会评估他的代码)称为)。
为此目的生成符号是常见的做法,可以使用 gensym
或以哈希结尾的符号,该语法引用将扩展为 gensym 调用。
`body#
评估(不合格!)符号body__34343__auto__
,其中数字在每次调用时都不同,并且保证每次都不同。
由于您在两个不同的语法引号中引用正文,因此我选择了 gensym
选项与 let
组合,以便只生成一个符号。
(defmacro defecho ; overloads stripped for brevity
[f assertions assert-failed-message]
(let [args-sym (gensym "body")] ; define a symbol for function arglist
`(defn ~f [& ~args-sym] ; define a function
~(when-not (nil? assertions) ; if given a function for input validation
`(assert (apply ~assertions ~args-sym) ; define the function to assert this as true
~assert-failed-message)) ; with a given error message
(conj ~args-sym (quote ~f)))))
关于clojure - 在宏中定义函数: can't use qualified name as parameter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33333136/