Вам нужно будет изменить 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
ожидал вектор имен полей, но, видимо, список тоже работает ... Вектор все еще определенно более идиоматичен.)