Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > LISP > глобальные переменные в макросах


Автор: kosmonaFFFt 16.8.2010, 13:03
Доброго времени суток... Столкнулся с проблемой при использовании в макросе глобальной переменной:

Код

(defparameter *defined-generic-getters* (make-array 0 :fill-pointer 0 :adjustable T))

...

(defmacro ...
      (let* ((defgeneric-getters (remove-if #'null
                                          (loop
                                             for slot in slots-list
                                             collect (unless (find slot *defined-generic-getters*)
                                                       (vector-push-extend slot *defined-generic-getters*)
                                                       `(defgeneric ,slot (self))))))
...


делаю так, чтобы не генерировать макросом одинаковых generic'ов...
Проблема в том, что данный код компилируется только после повторного объявления в REPL переменной *defined-generic-getters*,
а при попытки загрузки модуля через ASDF или простой загрузки файла, выдается что переменная *defined-generic-getters* не объявлена...

Можно ли как-либо с этим бороться, и если да, то как?
Заранее спасибо...

Автор: k0rvin 17.8.2010, 12:41
сейчас времени нет подробней разбираться, но можно объявлять глобальную переменную в теле макры, типа

Код

(defmacro ...
  (defvar *var* ...)
  (let* ...))

defvar объявляет переменную в глобальном окружении, независимо от того в каком окружении вызван + не пересвязывает ее в случае повторного объявления

Автор: k0rvin 17.8.2010, 13:24
вообще должно работать нормально. какой компилятор ты юзаешь?


Автор: kosmonaFFFt 18.8.2010, 18:16
SBCL под виндой и линуксом, и там и там поведение одинаковое...
Попробую в теле макроса объявить, отпишусь чего получится...

Автор: k0rvin 18.8.2010, 19:17
а если такой тестовый код скомпилить:

Код

(defparameter *x* "x")

(defmacro foo ()
  (print *x*))

(foo)

?

просто уж больно похоже, что у тебя в теле макры опечатка в имени переменной, но судя по приведённому тобой коду, опечатки нет =/

Автор: adejneka 18.8.2010, 21:53
Выдает ошибку
Цитата
; caught ERROR:
;   (during macroexpansion of (FOO))
;   The variable *X* is unbound.

Под SBCL работает такой вариант:
Код

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defvar *x* "x"))

(defmacro foo ()
  (print *x*))

(foo)

Правда, я не уверен, что он будет работать под Allegro CL.

Автор: k0rvin 19.8.2010, 17:15
Цитата(adejneka @ 18.8.2010,  21:53)
Выдает ошибку
Цитата
; caught ERROR:
;   (during macroexpansion of (FOO))
;   The variable *X* is unbound.

Под SBCL работает такой вариант:
Код

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defvar *x* "x"))

(defmacro foo ()
  (print *x*))

(foo)

Правда, я не уверен, что он будет работать под Allegro CL.

действительно, если выполнить (load "file.lisp"), то ошибки не будет, а при (load (compile-file "file.lisp")) она появляется. причину можно увидеть так:
Код

CL-USER> (pprint (macroexpand '(defvar *x* 0)))

(PROGN
 (EVAL-WHEN (:COMPILE-TOPLEVEL) (SB-IMPL::%COMPILER-DEFVAR '*X*))
 (EVAL-WHEN (:LOAD-TOPLEVEL :EXECUTE)
   (SB-IMPL::%DEFVAR '*X* (UNLESS (BOUNDP '*X*) 0) 'T NIL 'NIL
                     (SB-C:SOURCE-LOCATION))))
; No value
CL-USER> 


Цитата

Под SBCL работает такой вариант:
Код

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defvar *x* "x"))

(defmacro foo ()
  (print *x*))

(foo)

Правда, я не уверен, что он будет работать под Allegro CL.

скорее всего будет, но можно сделать и так:
Код

#.(defvar ...)
...

тогда переменная будет определена во время чтения до раскрытия макр времени компиляции

Автор: kosmonaFFFt 19.8.2010, 18:39
Спасибо за evel-when, мне кроме как под sbcl не надо... )

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)