【问题标题】:How To Make Determinations at Clojure Macro Expansion Time如何在 Clojure 宏扩展时做出决定
【发布时间】:2012-01-13 14:27:52
【问题描述】:

我相信我理解在宏扩展期间,宏无法访问函数可以访问的内容,因为扩展发生在编译时间之前。

但是,我无法理解如何在宏扩展时执行检查。

例如:

(defn gen-class [cl-nam]
    (fn [cmd & args]
        (condp = cmd
            :name (name cl-nam))))

(defmacro defnclass [cl-nam]
    `(def ~cl-nam (gen-class '~cl-nam)))

我想检查一下 cl-nam 不是一个序列。我想使用count并找出它的长度是> 1。

我知道我可以取消对以下宏中的 println 的引用,以便获得扩展时间消息。

(defmacro defnclass_info [cl-nam]
    `(do
        ~(println cl-nam)
        (def ~cl-nam (gen-class '~cl-nam))))

但是,我不确定如何检查 cl-nam 传递的内容。

我从几本书中阅读了很多 Clo​​jure 宏描述,我很困惑。 谢谢。

【问题讨论】:

    标签: clojure


    【解决方案1】:

    宏实际上只是一个函数。

    (defmacro defnclass-info
      [cl-name]
      (when (seq? cl-name)
        (throw (Exception. "cl-name must not be a sequence")))
      `(def ~cl-name (gen-class '~cl-name)))
    

    编辑: 也可以切换行为并为整个列表再次递归调用宏。你做什么,取决于你的要求。

    (defmacro defnclass-info
      [cl-name]
      (if (seq? cl-name)
        `(do ~@(for [cn cl-name] `(defnclass-info ~cn)))
        `(def ~cl-name (gen-class '~cl-name))))
    

    宏扩展正是“函数”返回的内容。因此,您可以完全灵活地处理宏参数。

    【讨论】:

    • 我假设您正在使用异常处理,将参数检查视为与宏的其余部分分开的实体。换句话说,如果它是 if 表单的一部分,您可以通过避免大量引用、取消引用和重新引用来简化它。你的方式更干净,看起来不那么凌乱。我只是想确保我理解它。
    • 您还可以根据参数切换行为。我添加一个例子。
    猜你喜欢
    • 1970-01-01
    • 2019-05-21
    • 1970-01-01
    • 2011-06-26
    • 1970-01-01
    • 1970-01-01
    • 2019-11-07
    • 1970-01-01
    • 2014-10-20
    相关资源
    最近更新 更多