我想要一个宏来定义返回它们被称为的形式的函数,例如: (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
答案 0 :(得分:4)
您不能使用合格的符号作为功能参数。观察
`body
评估为current-namespace/body
在语法引用中,您始终可以取消引用非语法引用以获取不合格的符号:
`~'body
评估为body
。 (请注意,此处的unquoting用于评估内部引用本身)。
但是,在这种情况下,您应该生成一个符号,因为如果用户在e中使用符号body
。 g assert-failed-message
的代码你不希望他body
与你的绑定被绑定(观察他的代码在实际调用生成的函数时被评估)。
通常的做法是为此目的生成符号,使用gensym
或以哈希结尾的符号,语法引用将扩展为gensym调用..
`body#
评估为(不合格!)符号body__34343__auto__
,其中每个调用的数字不同,并且每次都保证不同。
由于您从两个不同的语法引号中引用了body,因此我选择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)))))
答案 1 :(得分:0)
通过使用适当的繁重功能可以让您的生活变得更简单,并且仅将宏用于语法糖:
(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]
`(def ~f (echo-function (quote ~f) ~assertions ~assert-failed-message))))
(defn echo-function [f assertion assert-failed-message]
(fn [& body]
(when assertion
(assert (assertion body)
assert-failed-message))
(conj body f)))