Понимание разрешения символов с помощью макросов в Clojure

Я изучаю макросы в clojure. Мне нужна помощь с разрешением символов в макросах.

(ns macros.testing)

(def no (rand-int 10))

(defmacro drawer []
  `(do
     ~@(for [i (range no)]
     `(print ~i))))

(drawer) ;; This can resolve the global variable `no` properly


(defmacro drawer-2 [n]
  `(do
     ~@(for [i (range n)]
     `(print ~i))))


(drawer-2 10) ;; This works fine too
(drawer-2 n)  ;; This is not working, I'm unable to pass the global variable as an argument to the macro, although it's visible in the other case

Сообщение об ошибке class clojure.lang.Symbol cannot be cast to class java.lang.Number (clojure.lang.Symbol is in unnamed module of loader 'app'; java.lang.Number is in module java.base of loader 'bootstrap').

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

См. также этот ответ: stackoverflow.com/questions/60212576/…

Alan Thompson 26.10.2022 16:19
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Когда макрос оценивается, его аргументы передаются «как есть», без разрешения символов, как если бы все они были заключены в кавычки. Поэтому, если вы передадите n, внутри макроса это будет символ n, а не значение, содержащееся в соответствующей переменной. Если пройдете (inc 10), будет '(inc 10). И так далее.

Итак, в drawer(range no) работает, потому что no относится к переменной, связанной с результатом (rand-int 10).

В drawer-2 аргумент n имеет значение (symbol "n") (или просто 'n) во время вычисления макроса. И (range 'n) не может работать — это как раз то, о чем вы видели исключение «не может преобразовать символ в число».

Чтобы исправить это, вы можете явно разрешить переданный символ, используя resolve (это @ необходимо для получения значения разрешенной переменной):

(def value 10)

(defmacro drawer-2 [n]
  (let [n (if (symbol? n)
            @(resolve n)
            n)]
    `(do
       ~@(for [i (range n)]
           `(print ~i)))))

(drawer-2 value)

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