Я хотел бы иметь макрос, который я назову нечто определения. Нечто определения создаст функцию и затем добавит эту функцию к набору.
Таким образом, я мог звонить
(def-foo bar ...)
(def-foo baz ...)
И затем был бы некоторый набор, например, все-foos, который я мог назвать:
all-foos
=> #{bar, baz}
По существу я просто стараюсь не повторять меня. Я мог, конечно, определить функции нормальным способом, (defn панель...) и затем записать набор вручную.
Лучшая альтернатива, и более простой, чем макро-идея, должна была бы сделать:
(def foos #{(defn bar ...) (defn baz ...)} )
Но мне все еще любопытно относительно того, существует ли хороший путь к макро-идее работать.
Вы хотите получить набор, в котором есть имена функций (т.е. набор символов), или набор, содержащий переменные (которые разрешаются в функции)? Если вам нужно первое, вы можете добавить символы к атому в макросе во время компиляции, как в версии Грега Хармана.
Если вы хотите последнее, ваш макрос должен расшириться до кода, который выполняет обмен атомами после определения функции. Помните, что макросы выполняются во время компиляции, а результат с расширенным макросом выполняется во время выполнения; сама функция недоступна до времени выполнения.
(def all-foos (atom #{}))
(defmacro def-foo [x]
`(let [var# (defn ~x [] (println "I am" '~x))]
(swap! all-foos conj var#)))
Если вы хотите иметь возможность вызывать функции, например, из этого набора, вам необходимо использовать последнюю версию.
user> (def-foo foo)
#{#'user/foo}
user> (def-foo bar)
#{#'user/foo #'user/bar}
user> ((first @all-foos))
I am foo
nil
Попросите макрос добавить имя новой функции в ваш набор перед созданием функции, например:
(def *foos* (atom (hash-set)))
(defmacro def-foo [name]
(swap! *foos* conj name)
`(defn ~name
[]
(println "This is a foo!")))
Результат:
user=> (def-foo bar)
#'user/bar
user=> (def-foo baz)
#'user/baz
user=> (bar)
This is a foo!
nil
user=> (baz)
This is a foo!
nil
user=> *foos*
#<Atom@186b11c: #{baz bar}>