【问题标题】:Question about clojure namespaces and macros关于clojure命名空间和宏的问题
【发布时间】:2010-02-25 17:52:05
【问题描述】:

假设我有一堆命名空间(apple、banana、orange)。在这些命名空间中,我使用了eat 宏,它调用(不是“生成”,调用peel 函数。 peel 函数对于每种水果都不同,但宏是相同的,而且相当大,所以我想创建一个包含 eat 宏的 fruit 命名空间。但是当我从apple 命名空间调用eat 宏时,eat 宏应该调用apple/peel 函数。

为了说明(但这不起作用):

(ns fruit)
(defmacro eat [] (peel))

(ns apple)
(defn peel [] (prn "peeled apple"))
(fruit/eat)

(ns banana)
(defn peel [] (prn "peeled banana"))
(fruit/eat)

强调一下,这意味着当且仅当宏展开时才应调用剥离函数,如本例所示。

(ns apple)
(defn peel [] (prn "peeled apple"))
(defmacro eat [] (peel))
(macroexpand-1 '(eat))

那么,关于如何结合宏和多态性有什么想法吗?

【问题讨论】:

    标签: macros clojure


    【解决方案1】:

    您所描述的不是多态性,而是所谓的本地捕获。您希望 eat 宏“捕获”peel 的本地定义。

    这在大多数 Lisps 中被认为是不好的风格,尤其是 Clojure,因为它可能导致微妙和不可预测的错误。

    更好的解决方案是在调用时将正确的 peel 传递给 eat 宏:

    (ns fruit)
    (defmacro eat [peeler] `(~peeler))
    
    (ns apple)
    (defn peel [] (prn "Peeled an apple"))
    (fruit/eat peel)
    

    如果你真的想做本地捕获,你可以在宏中用 ~' (unquote-quote) 强制它:

    (ns fruit)
    (defmacro eat [] `(~'peel))
    

    【讨论】:

    • 这不是我的意思。我希望在展开时间调用 peel 函数。我已经澄清了这个问题。
    • 我明白,将提供另一个答案。
    【解决方案2】:

    正如已编辑问题中所解释的,这与本地捕获略有不同,因为您不是在宏扩展中使用 peel,而是在宏本身的执行中。

    这很困难,因为宏不评估它们的参数。即使您将 peel 作为参数传递给 eat,在宏的主体内它也只是一个符号,而不是可调用函数。

    做你想做的事(不使用eval)的唯一方法是在编译时解析符号:

    (defmacro eat []
       ((var-get (resolve 'peel)))
       ... return the expansion of "eat" ...)
    

    resolve 函数接受一个符号并返回它在当前命名空间中映射到的 Var。获得 Var 后,您可以使用 var-get 检索实际函数(Var 的值)。额外的一组括号调用该函数。

    不用说,这是一个非常不寻常的设计,可能需要重新考虑。

    【讨论】:

      【解决方案3】:
      (defmacro eat [] ((var-get (resolve 'peel))))
      

      请注意,您正在滥用命名空间。

      【讨论】:

        【解决方案4】:

        编辑:对不起。我已经发布了以下内容。但是您说的是“调用,而不是生成”剥离功能。所以我写的可能不是你想要的,虽然它看起来会得到预期的结果。

        简单地引用 (peel) 对我有用。

        (ns fruit)
        (defmacro eat [] '(peel))
        
        (ns apple)
        (defn peel [] (prn "peeled apple"))
        (fruit/eat)
        
        (ns banana)
        (defn peel [] (prn "peeled banana"))
        (fruit/eat)
        

        【讨论】:

        • 谢谢,但确实不是我的意思。它确实在这里得到了想要的结果,但在我的实际用例中却没有。
        猜你喜欢
        • 1970-01-01
        • 2013-06-12
        • 1970-01-01
        • 1970-01-01
        • 2011-03-27
        • 1970-01-01
        • 2011-02-28
        • 2020-01-31
        • 1970-01-01
        相关资源
        最近更新 更多