by" artificial",我的意思是使用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)
"*")))
这样做的正确方法是什么?
答案 0 :(得分: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 :(得分:2)
其中一个“使用返回带PROGN
节的DEFPARAMETER
或”使用PROCLAIM
的宏,它是一个函数,而不是宏“。
答案 2 :(得分: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)