使用" artificial"声明全局变量符号

时间:2014-09-08 12:30:35

标签: common-lisp

by" artificial",我的意思是使用internmake-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)
                                                        "*")))

这样做的正确方法是什么?

3 个答案:

答案 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)))

现在您可以使用索引(在此示例中为xy)访问表数组:

(gethash (aref *char-counts* x y) :foo)