Динамические записи в Clojure

При попытке запустить следующий код из REPL (пытается поиграть с динамическими записями):

(defrecord (symbol "rec2") (vec (map symbol ["f1" "f2"])))

У меня ошибка CompilerException java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol, compiling:(NO_SOURCE_PATH:23)

Я спрашиваю себя, где я генерирую этот PersistentList, учитывая, что:

user=> (symbol "rec2")
rec2
user=> (vec (map symbol ["f1" "f2"]))
[f1 f2]

Но мой настоящий вопрос заключается в том, почему работает следующий код:

user=> (defrecord rec2 [f1 f2])
user.rec2

Я также попробовал:

user=> (clojure.core/defrecord (clojure.core/symbol "rec1") (vec (clojure.core/map clojure.core/symbol ["f1" "f2"])))
CompilerException java.lang.RuntimeException: Can't refer to qualified var that doesn't exist, compiling:(NO_SOURCE_PATH:40)

(квалифицированная переменная? Единственное отличие состоит в том, что я полностью определяю имена функций WHICH EXIST, BTW) Очевидно, что мне не хватает чего-то в моем понимании макросов defjord Clojure, но я подумал, что макрос - это просто модификаторы AST, поэтому, если я дам ему Символ или что-то, что превращается в символ, это одно и то же, поэтому я хотел бы, чтобы кто-то объяснил мне, почему нормальная форма работает, а другие нет!

ТИА!

1 ответ

Решение

Проблема заключается в следующем: defrecord является макросом и все аргументы не оцениваются. Они перешли на макрос, так что он получает (symbol "rec2") - список, который содержит 2 элемента: символ и строку, а не rec2 как вы ожидаете. Вы можете попробовать следующее:

(eval `(defrecord ~(symbol "rec2") ~(vec (map symbol ["f1" "f2"])))) 

Создает список (defrecord rec2 [f1 f2]) и затем оценивает это.
Но я не думаю, что это хорошая идея - динамически оценивать некоторый код. Может быть, есть другой способ сделать это.

Другие вопросы по тегам