2010-02-25 58 views
6

假设我有一堆命名空间(苹果,香蕉,桔子)。在这些命名空间中,我使用调用eat宏,该宏调用(不是“生成”,调用peel函数。每个水果的peel函数是不同的,但宏是相同的,并且相当大,所以我想要创建一个包含eat宏的名称空间fruit。但是当我从apple名称空间调用eat宏时,eat宏应该调用apple/peel函数。关于clojure命名空间和宏的问题

为了说明(但不工作):

(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)) 

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

回答

1

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

简单引用(peel)为我工作。

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

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

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

谢谢,但事实上并非我的意思。它在这里得到了期望的结果,但不是在我的实际使用情况中。 – 2010-03-02 15:17:55

2
(defmacro eat [] ((var-get (resolve 'peel)))) 

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

7

你所描述的不是多态,而是所谓的本地捕获。你想吃宏宏来“捕获”本地定义果皮

在大多数Lisp中,这被认为是不好的风格,尤其是Clojure,因为它会导致细微和不可预知的错误。

更好的解决方案是通过正确的剥离宏,当你把它叫做:

(ns fruit) 
(defmacro eat [peeler] `(~peeler)) 

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

如果你真的想这样做本地捕获,您可以用〜”迫使它(引文结束引号)宏:

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

这不完全是我的意思。我希望在展开时间内调用'peel'函数。我澄清了这个问题。 – 2010-03-02 15:15:46

+0

我明白了,会提供另一个答案。 – 2010-03-05 01:24:38

3

作为编辑的问题解释说,这是当地捕获略有不同,因为你不使用剥离在宏展开中,而是在宏本身的执行中。

这很困难,因为宏不评估它们的参数。即使你通过果皮作为参数,在宏体内它只是一个符号,而不是一个可调用的函数。

做你想要什么(不使用EVAL)的唯一途径是解决在编译时符号:

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

决心功能需要一个符号,并返回它映射瓦尔到当前的命名空间。获得Var后,可以用var-get检索实际功能(Var的值)。额外的一组圆括号称这个函数。

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