Возврат макроса из макроса в Clojure - PullRequest
2 голосов
/ 12 января 2012

Как написано в другом посте, я пишу компилятор Shen в Clojure. Для этого мне нужен макрос / функция, которая получает символ в качестве параметра, и если функция Shen связана с ним, она возвращает функцию, а если символ определен как макрос Clojure, она должна возвращать макрос, поэтому ((function or) true false) должно выдавать то же самое результат как (or true false).

Мой макрос в настоящее время выглядит так:

(defmacro kl/function [x] 
(cl/let [fn (symbol (cl/str (name x) "__fnPoF__"))]
    (if (function? fn) `(eval ~fn) `(quote ~x))))

Постфикс "__fnPoF__" присутствует из-за двойного пространства имен в Shen. (Значение и функция могут быть назначены одному и тому же символу.)

Моя проблема сейчас в том, что ((function or) true false) оценивается как ложное, потому что оно оценивается как ('or true false), но если я пропущу "цитату" (x вместо `(quote ~x), я получу следующее исключение:

kl=> (function *)
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'kl/*, compiling:(NO_SOURCE_PATH:8)

У кого-нибудь есть идеи, как решить эту проблему?

1 Ответ

3 голосов
/ 12 января 2012

Вы не можете «вернуть» макрос, потому что у макросов нет значения.Но вы можете заставить (функцию или) расширяться до символа или;тогда обычные механизмы расширения / оценки Clojure будут делать то, что вы хотите.Так что, хотя я не знаю, как работает Шен, кажется, что простое изменение было бы следующим:

(defmacro kl/function [x] 
  (cl/let [fn (symbol (cl/str (name x) "__fnPoF__"))]
    (if (function? fn)
      `(eval ~fn)
      x)))

В целом, это eval кажется мне катастрофой ожиданияпроизойдет.Я сильно сомневаюсь, что eval необходимо для ваших целей.

...