clojure - 在宏中定义函数: can't use qualified name as parameter

标签 clojure

我想要一个宏来定义返回它们被调用的形式的函数,例如(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/

    相关文章:

    用不同数量的参数重载的函数

    recursion - 递归使用 `lazy-seq`是否会占用堆栈帧?

    Java 8,用于 Mac OS X 上的 IntelliJ

    oop - "Many functions operating upon few abstractions"原理 vs 面向对象

    从 Haskell 到 Clojure

    clojure - Clojure 中的高阶函数

    heroku - 如何在 Heroku 中部署和运行 clojurescript 应用程序

    clojure - 如何在 Clojure 中更扁平的数据结构中获得相同的值?

    loops - 将值添加到匹配谓词的第一个列表(列表)

    clojure:子集的排列?