Динамические записи в 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])
и затем оценивает это.
Но я не думаю, что это хорошая идея - динамически оценивать некоторый код. Может быть, есть другой способ сделать это.