распространенный шут: как макрос может определять другие методы / макросы с программно сгенерированными именами? - PullRequest
13 голосов
/ 05 мая 2011

Я понял, что определенный раздел моего кода состоит из групп методов, которые выглядят одинаково (как у меня несколько трио: вспомогательная функция, которая вызывается двумя другими функциями, предназначенными для программиста). Я пытаюсь написать макрос, который определит эти три функции для меня, так что все, что мне нужно сделать, это вызвать макрос. Но моя попытка приводит к функциям defuns и вызовам функций, которые заключают в кавычки строки вместо сгенерированных имен в качестве новых символов. Что я делаю не так?

Пример (неверный код)

(defmacro def-trio (base-name)
  (let 
    ((helper-name (format nil "helper-~a" base-name))
     (method-1 (format nil "~a-1" base-name))
     (method-2 (format nil "~a-2" base-name)))
    `(progn 
          (defun ,helper-name () 'helper-called)
          (defun ,method-1 () (,helper-name) '1-called)
          (defun ,method-2 () (,helper-name) '2-called))))

Теперь происходит следующее:

(def-trio my-trio)

==>

(PROGN (DEFUN "helper-MY-TRIO" () 'HELPER-CALLED)
       (DEFUN "MY-TRIO-1" () ("helper-MY-TRIO") '1-CALLED)
       (DEFUN "MY-TRIO-2" () ("helper-MY-TRIO") '2-CALLED))

Кроме того, после того, как я узнаю, как заставить это работать, есть ли какие-то дополнительные ошибки, если бы этот макрос определял другие макросы вместо других функций? Я читаю Как мне написать макрос, определяющий макрос, в общем lisp , но я думаю, что мой вопрос немного отличается, потому что я спрашиваю о программно сгенерированных символах / именах. Я открыт для исправления, хотя :) Спасибо!

Ответы [ 2 ]

8 голосов
/ 05 мая 2011

Попробуйте: (defmacro def-trio (base-name) ; changes: (let<strong>*</strong> ; 3. (<strong>(package (symbol-package base-name))</strong> ; 2. (helper-name <strong>(intern</strong> (format nil "<strong>HELPER</strong>-~a" base-name)<strong> package)</strong>) ; 1. 4. (method-1 <strong>(intern</strong> (format nil "~a-1" base-name) <strong>package</strong>)) ; 1. (method-2 <strong>(intern</strong> (format nil "~a-2" base-name) <strong>package</strong>)) ) ; 1. `(progn (defun ,helper-name () 'helper-called) (defun ,method-1 () (,helper-name) '1-called) (defun ,method-2 () (,helper-name) '2-called) )))

Следующие изменения были внесены в ваше первоначальное определение - первое изменение является решающим:

  1. Вставлено каждое из имен вычисляемых символов втот же пакет, что и базовое имя, используя (intern ... package).
  2. . Введена переменная package, связанная с пакетом поставляемого символа base-name.
  3. Изменено let на let*, чтобы разрешить ссылаться на вновь введенную переменную package в последующих переменных.
  4. Изменен префикс вспомогательного метода на верхний регистр, чтобы соответствовать соглашению для нормальных символов Lisp.
5 голосов
/ 05 мая 2011

Используйте INTERN, чтобы превратить сгенерированные строки с именами функций в символы.

...