определить и разрешить в том же макросе clojure - PullRequest
0 голосов
/ 27 сентября 2018

Я хочу добиться возврата разрешенного символа пространства имен в макросе, который недавно определил сам символ:

(ns my-namespace)

(defmacro def&resolve [a b]
  `(do
     (def ~a 12)
     (def ~b ~(resolve a))))

(def&resolve foo bar)
bar ;=> nil

В примере bar возвращает ноль.Я, однако, хочу, чтобы он возвратил my-namespace.foo.Я знаю, что это не работает, поскольку во время вызова resolve, a еще не определено.Однако для моего варианта использования [1] мне нужно, чтобы a было разрешено во время расширения макроса.

В следующем запуске я хотел объявить a во время расширения макроса (это вообще имеет смысл?) И, таким образом, заставить его присутствовать в текущем ns при вызове resolve.

(defmacro def&resolve [a b]
  (declare a)
  `(do (def ~a 12)
       (def ~b ~(resolve a))))

(def&resolve foo bar)
bar ;=> nil

тоже не работает.

Как я могу определить что-либо и разрешить это в самом пространстве имен расширения макроса?


[1] Мой пример использования следующий: я хочу определить набор функций и добавитьэто к метаинформации def-привязки (таким образом, мне это нужно во время расширения макроса).В настоящее время я храню только символы без пространства имен, в котором были определены функции.

Ответы [ 3 ]

0 голосов
/ 27 сентября 2018

, так как переменная будет определена / создана во время выполнения, как только макрос завершит свою работу и уйдет, макрос может вместо этого предсказать, как будет названа переменная, и создать символ напрямую, а не совершать циклический переходчерез пространство имен и обратно

Давайте сначала сделаем это вручную

user> (def foo)
#'user/foo
user> (resolve 'foo)
#'user/foo

, что выглядит правильно, теперь давайте сделаем это, создав символ:

user> (symbol (str *ns* "/" "foo"))
user/foo

и скопируем этов определение макроса:

user> (defmacro def&resolve [a b]
        `(do
           (def ~a 12)
           (def ~b ~(symbol (str *ns* "/" "foo")))))
#'user/def&resolve

и протестируйте его

user> (def&resolve foo bar)
#'user/bar

user> bar
12

Этот метод предпочтительнее подхода intern для создания символа в пространстве имен с использованием фиктивного значения, во время расширения макроса, затем resolve, используя его также во время расширения макроса.В результате чего же значение.Преимущество этого подхода состоит в том, что он выполняет работу по разрешению во время расширения макроса, как в исходном вопросе

user> (do (intern *ns* 'a :dummy-value)
          (resolve 'a))
#'user/a

, хотя я рекомендую использовать подход генерации символов.

0 голосов
/ 28 сентября 2018

Помогает вложение синтаксической кавычки, с дополнительным цитированием ~ a:

(defmacro def&resolve
  [a b]
  `(do
     (def ~a 12)
     (def ~b ~`(resolve '~a))))
#'test-project.core/def&resolve

test-project.core=> (macroexpand '(def&resolve foo bar))
(do (def foo 12) (def bar (clojure.core/resolve (quote foo))))

test-project.core=> (def&resolve foo bar)
#'test-project.core/bar

test-project.core=> foo
12

test-project.core=> bar
#'test-project.core/foo

Если вы действительно хотите получить значение foo в строке, тогда вам нужно разыскивать (@) varразрешение:

(defmacro def&resolve
  [a b]
  `(do
     (def ~a 12)
     (def ~b @~`(resolve '~a))))

test-project.core=> (def&resolve foo bar)
#'test-project.core/bar
test-project.core=> bar
12
0 голосов
/ 27 сентября 2018
(ns another-namespace)

(defmacro def&resolve [a b]
  `(do
     (def ~a 12)
     (def ~b (resolve '~a))))

(macroexpand-1 '(def&resolve foo bar))
#=> (do (def foo 12) (def bar (clojure.core/resolve (quote foo))))

(def&resolve foo bar)
bar
#=> #'another-namespace/foo
...