2010-07-25 55 views
7

我想在編譯器中使用clojure,因此需要參數化調用deftype;然而,我很難讓類型提示通過。請看下面的代碼:使用Clojure deftype作爲參數化函數

(defn describe [x] 
    (let [fields (.getDeclaredFields x) 
     names (map #(.getName %) fields) 
     types (map #(.getType %) fields)] 
    (interleave types names))) 

(defn direct [] (deftype direct-type [^int x])) 
(defn indirect-helper [] (list ^int (symbol "x"))) 
(defn indirect [] (eval `(deftype ~(symbol "indirect-type") ~(indirect-helper)))) 

並在下屆會議從REPL:

Clojure 1.2.0-master-SNAPSHOT 
1:1 user=> #<Namespace dataclass> 
1:2 dataclass=> (direct) 
dataclass.direct-type 
1:3 dataclass=> (indirect) 
dataclass.indirect-type 
1:4 dataclass=> (describe direct-type) 
(int "x") 
1:5 dataclass=> (describe indirect-type) 
(java.lang.Object "x") 

注意,間接式生成的類已經失去了^ INT暗示直下式了。我如何獲得這些提示?

回答

7

你需要改變indirect-helper閱讀

(defn indirect-helper [] [(with-meta (symbol "x") {:tag 'int})]) 

的原因是^int解析爲^其次int; Clojure 1.2中的^引入了閱讀器元數據(在1.1中,您將使用#^,它仍然有效,但在1.2中不推薦使用)。因此^int xdirect得到讀在作爲clojure.lang.Symbol他的名字是"x"和其元數據映射爲{:tag int}(與int這裏存在本身的象徵)。 (符號的最後一個組成部分 - 其命名空間 - 在這種情況下nil。)

在從問題文本^int被附接到(symbol "x")版本的indirect-helper - 列表包括所述符號symbol和字符串"x" (特別意味着(list ^int (symbol "x"))評估爲1個元素的列表)。一旦(symbol "x")被評估,此「類型提示」就會丟失。爲了解決問題,需要將元數據附加到由(symbol "x")生成的實際符號的一些方法。

現在在這種情況下,該符號是在運行時生成的,因此您不能使用reader元數據將類型提示附加到它。輸入with-meta,它在運行時附加的元數據(而且常常是有用的書面宏,因爲它是在這裏同樣的原因),這一天被保存:

user> (indirect) 
user.indirect-type 
user> (describe indirect-type) 
(int "x") 

(順便說一句,我認爲deftype預期字段名的向量,但顯然一個列表的作品以及...一個向量仍然肯定更習慣。)