Могу ли я создать макрос clojure, который позволит мне получить список всех функций, созданных этим макросом? - PullRequest
5 голосов
/ 02 июня 2010

Я хотел бы иметь макрос, который я назову def-foo. Def-foo создаст функцию, а затем добавит эту функцию в набор.

Чтобы я мог позвонить

(def-foo bar ...)

(def-foo baz ...)

И тогда будет некоторый набор, например all-foos, который я мог бы назвать:

all-foos
=> #{bar, baz}

По сути, я просто стараюсь не повторяться. Конечно, я мог бы определить функции обычным способом (defn bar ...), а затем написать набор вручную.

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

(def foos #{(defn bar ...)    (defn baz ...)} )

Но мне все еще любопытно, есть ли хороший способ для реализации идеи макроса.

Ответы [ 2 ]

5 голосов
/ 02 июня 2010

Хотите ли вы получить набор с именами функций (то есть набор символов) или набор с переменными (которые разрешают функции)? Если вы хотите первое, вы можете добавить символы для атома в макросе во время компиляции, как версия Грега Хармана.

Если вы хотите последнее, ваш макрос должен расшириться до кода, который выполняет обмен атомами после определения функции. Помните, что макросы выполняются во время компиляции, а результат развертывания макроса запускается во время выполнения; Сама функция недоступна до времени выполнения.

(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
5 голосов
/ 02 июня 2010

Пусть макрос добавит имя новой функции в ваш набор перед созданием функции, например:

(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}>
...