2014-09-08 2 views
0

Под «искусственным» подразумевается один, созданный из строки с использованием intern или make-symbol.
У меня есть часть моего кода, объявляющий до 49 глобальных переменных:Объявить глобальную переменную с помощью «искусственного» символа

(defparameter *CHAR-COUNT-1-1* (make-hash-table)) 
... 
(defparameter *CHAR-COUNT-1-7* (make-hash-table)) 
... 
(defparameter *CHAR-COUNT-7-7* (make-hash-table)) 

я думал, вместо этого, я мог бы создать функцию, чтобы сделать все, что:

(loop for n from 1 to 7 do 
    (loop for i from 1 to 7 do 
    (defparameter (symbol-value (intern (concatenate 'string "*CHAR-COUNT-" (write-to-string n) "-" (write-to-string i) "*"))) 
        (make-hash-table :test 'equalp)))) 

Но получаю ошибку (sbcl):

unhandled SIMPLE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING 
            {1002978EE3}>: 
    Can't declare a non-symbol as SPECIAL: (SYMBOL-VALUE 
              (INTERN 
              (CONCATENATE 'STRING "*CHAR-COUNT-" 
                 (WRITE-TO-STRING N) "-" 
                 (WRITE-TO-STRING I) 
                 "*"))) 

Каков правильный способ для этого?

+4

Встраивание размерный данные в имя переменной кажется, что это действительно должно быть различные данные структуры, как двухмерный массив. Но если вы действительно хотите это сделать, один простой способ - через макролет. – Xach

+0

Снимите SYMBOL-VALUE для запуска; вы не хотите значения символа ... вам также понадобится либо макроэкземпляр DEFPARAMETER. – BRFennPocock

ответ

2

Один из «использование макроса, который возвращает PROGN с DEFPARAMETER stanzas» или «использовать PROCLAIM, это функция, а не макрос».

5

Defparameter - это макрос, а не функция. Это означает, что он определяет специальный синтаксис. Форма defparameter должна иметь символ в качестве второго аргумента, но вы предоставляете список:

(symbol-value (intern (concatenate 'string "*CHAR-COUNT-" (write-to-string n) "-" (write-to-string i) "*"))) 

То, что вы хотите это форма как

(progn 
    (defparameter *foo-1-1* (make-hash-table ...)) 
    ... 
    (defparameter *foo-n-n* (make-hash-table ...))) 

Вы, кажется, достаточно хорошо знаком с петлей и создание символов для создания этого списка; просто изменить

(loop … do (loop … do (defparameter …))) 

в

`(progn 
    ,@(loop … nconcing 
     (loop … collecting 
     `(defparameter ,(intern …) …)))) 

и вы можете получить необходимую форму. Тогда это всего лишь вопрос поместить все это в макрос.

(defmacro … (…) 
    `(progn 
    ,@(loop … nconcing 
     (loop … collecting 
      `(defparameter ,(intern …) …))))) 

и вызов макроса.

1

Правильный способ заключается в использовании правильной структуры данных вместо кодирования измерений в именах символов. Вы действительно хотите вычислить и кодировать имена символов в любое время, когда хотите получить доступ к правильной таблице?

(defparameter *char-counts* (make-array '(7 7))) 

(dotimes (i 49) ; or (reduce #'* (array-dimensions *char-counts*)) 
    (setf (row-major-aref *char-counts* i) (make-hash-table))) 

Теперь вы можете получить доступ к массиву таблиц только с индексами (x и y в этом примере):

(gethash (aref *char-counts* x y) :foo) 
Смежные вопросы