Определение и доступ к переменным в локальной среде - PullRequest
2 голосов
/ 26 июня 2019

После долгого времени изучения CL и практики в качестве хобби в различных небольших проектах у меня все еще есть некоторые пустые области на моей личной карте CL.Недавно у меня было несколько функций, использующих одну и ту же конструкцию let, и я подумал о написании макроса, который делает код более лаконичным:

(defmacro with-context (&body body)
   `(let ((context (make-array 4 :element-type 'fixnum
                                 :initial-contents '(0 1 2 3))))
     ,@body))

, чтобы позже я мог определять функции какминимальный пример):

(defun test-a ()
  (with-context
    (setf (aref context 3)
          (+ (aref context 0) (aref context 1)))
    context))

Теперь мне было интересно, смогу ли я сократить выражения (aref context n) с помощью макроса / функции, например (context n).

(defun context (n)
  (aref context n))

Но переменная context неизвестно во время компиляции, конечно.Я просто не знаю, есть ли у меня случай базового недопонимания или как я могу сказать Лиспу, чего я на самом деле хочу.Итак, мой вопрос в основном, если это возможно, и если это хорошая идея.

Ответы [ 2 ]

4 голосов
/ 26 июня 2019

Что не так с локальной функцией?

(defmacro with-context (&body body)
  `(let ((context (make-array 4 :initial-contents '(0 1 2 3))))
     (flet ((context (n)
              (aref context n)))
       ,@body)))

Настройка тоже:

(defmacro with-context (&body body)
  `(let ((context (make-array 4 :initial-contents '(0 1 2 3))))
     (flet ((context (n)
              (aref context n))
            ((setf context) (new n)
              (setf (aref context n) new)))
       ,@body)))
3 голосов
/ 26 июня 2019

Вы можете добавить macrolet в расширение макроса:

(defmacro with-context (&body body)
  (with-gensyms (i)
    `(let ((context (make-array 4 …)))
       (macrolet ((context (,i)
                    `(aref context ,,i)))
         ,@body))))

Некоторые личные заметки:

Мне не нравятся анафорические макросы, поэтому я обычно позволяю пользователю определять имядля контекста.Это было бы странно с макролетом context.Тогда я, возможно, приду к выводу, что все, что мне нужно, это функция make-standard-context и продолжаю использовать let.Я думаю, что это соответствует общему руководству «будь условен».

...