Создание операторов core.logic с помощью макросов

Я пытаюсь динамически создать оператор core.logic, «заполнив пробелы». Вот простой пример:

(def number 42)
(def stmt `(run* [q] (== q ~number))
(eval stmt)

Однако я получаю clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: No such var: user/q, compiling:(null:20:12).

Я пробовал каждую комбинацию цитирования, раскавычивания и раскавычивания, но я не могу понять это. Как мне вставить q?

(И, сделав шаг назад, правильно ли строить такие утверждения?)


person Frederik    schedule 21.04.2015    source источник


Ответы (2)


Поскольку вы используете синтаксическую кавычку, символ q заключен в кавычки, как и в текущем пространстве имен.

Закавычите его без оговорок, но раскавычивайте это, чтобы не заключать в кавычки синтаксические кавычки:

(def stmt `(run* [~'q] (== ~'q ~number)))

Или создать символ

(def stmt `(run* [q#] (== q# ~number)))
person Leon Grapenthin    schedule 21.04.2015
comment
Генерация символа q# кажется подходящим вариантом, учитывая, что это менее запутанно, чем ~'q без кавычек. - person Frederik; 23.04.2015
comment
Это также более гигиенично, если e. грамм. Число было формой с другим q в нем. - person Leon Grapenthin; 23.04.2015

Если ваши логические операторы хранятся в виде строк, вы можете использовать read-string, чтобы получить форму Clojure, а затем вызвать для нее eval:

(def number 42)
(def stmt-as-str "(run* [q] (== q number))")
(eval (read-string stmt-as-str))
> (42)

Или, если это просто форма:

(def stmt-as-form '(run* [q] (== q number)))
(eval stmt-as-form)
> (42)

Примечание: `, ~ или ~@ обычно используются в определении макроса.

person T.Gounelle    schedule 21.04.2015
comment
read-string противоречит цели использования структур данных Clojure. Мне нужны возможности макроса для более сложных операций без кавычек внутри макроса run*. - person Frederik; 23.04.2015