Использование Clojure deftype в качестве параметризованной функции - PullRequest
7 голосов
/ 25 июля 2010

Я пытаюсь использовать 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, которые прямого типаесть.Как мне получить эти подсказки для выполнения?

1 Ответ

7 голосов
/ 26 июля 2010

Вам нужно будет изменить indirect-helper на

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

Причина в том, что ^int анализируется как ^, за которым следует int; ^ в Clojure 1.2 вводит метаданные считывателя (в 1.1 вы бы использовали #^, который все еще работает, но не рекомендуется в 1.2). Таким образом, ^int x в direct получает , читаемую в как clojure.lang.Symbol, чье имя "x" и чья карта метаданных {:tag int} (где int здесь сам является символом) (Последний компонент символа - его пространство имен - в данном случае nil.)

В версии indirect-helper из текста вопроса ^int присоединяется к (symbol "x") - список, содержащий символ symbol и строку "x" (в частности, значение (list ^int (symbol "x")) оценивается как список из 1 элемента). Эта «подсказка типа» теряется при оценке (symbol "x"). Чтобы исправить ситуацию, необходим какой-либо способ прикрепления метаданных к фактическому символу, сгенерированному (symbol "x").

Теперь в этом случае символ генерируется во время выполнения, поэтому вы не можете использовать метаданные читателя, чтобы присоединить к нему подсказку типа. Введите with-meta, который присоединяет метаданные во время выполнения (и часто полезен при написании макросов по той же причине, что и здесь), и день сохраняется:

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

(Кстати, я думал deftype ожидал вектор имен полей, но, видимо, список тоже работает ... Вектор все еще определенно более идиоматичен.)

...