使用Clojure deftype作为参数化函数

Using Clojure deftype as a parameterized function

我正在尝试在编译器中使用clojure,因此需要参数化对deftype的调用;但是,我很难使类型提示得以贯彻。请考虑以下代码:

1
2
3
4
5
6
7
8
9
(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的以下会话:

1
2
3
4
5
6
7
8
9
10
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提示具有。如何获得这些提示?


您需要将indirect-helper更改为

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

,原因是^int解析为^,后跟int;在Clojure 1.2中,^引入了阅读器元数据(在1.1中,您将使用#^,它仍然有效,但在1.2中已弃用)。因此,将direct中的^int x作为名称为"x"且元数据映射为{:tag int}clojure.lang.Symbol读入(其中int本身是符号)。 (在这种情况下,符号的最后一个组成部分-其名称空间-为nil。)

在问题文本^intindirect-helper版本中,附加到(symbol"x")-包含符号symbol和字符串"x"的列表(尤其意味着(list ^int (symbol"x"))的结果为1个元素的列表)。一旦评估(symbol"x"),此\\\\"类型提示\\\\"将丢失。为了解决问题,需要某种方式将元数据附加到(symbol"x")生成的实际符号上。

现在,在这种情况下,符号是在运行时生成的,因此您不能使用读取器元数据来附加类型提示。输入with-meta,它会在运行时附加元数据(由于与此处相同的原因,在写宏时通常很有用)并保存了一天:

1
2
3
4
user> (indirect)
user.indirect-type
user> (describe indirect-type)
(int"x")

(顺便说一句,我认为deftype本来应该是字段名称的向量,但显然列表也可以工作。向量肯定还是比较惯用的。)