假设我有一堆命名空间(苹果,香蕉,橙色)。在这些 namespace 中,我使用eat宏,该宏调用peel函数(而不是“generates”,调用)。每种水果的peel函数都不同,但是宏是相同的,并且相当大,因此我想创建一个包含fruit宏的eat命名空间。但是,当我从eat命名空间调用apple宏时,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)

要强调的是,这意味着在宏扩展时(仅在此示例中),才应调用pere函数。
(ns apple)
(defn peel [] (prn "peeled apple"))
(defmacro eat [] (peel))
(macroexpand-1 '(eat))

那么,关于如何组合宏和多态性的任何想法?

最佳答案

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

在大多数Lisps中,尤其是Clojure,这被认为是不良样式,因为它可能导致细微且不可预测的错误。

更好的解决方案是在调用它时将正确的果皮传递给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))

10-08 16:44