使用defparameter定义变量,其名称在运行时确定

时间:2014-03-12 17:15:38

标签: lisp common-lisp

我想使用其中一个参数动态创建一个带有defmethoddefun的哈希表来创建名称。例如:

(defun foo (arg)
  (let ((NAME (read-from-string (format nil "\*~S\*" arg))))
    (defparameter NAME (make-hash-table))))

当然,foo使用符号NAME创建哈希表,而不是NAMElet的值。如何获取NAME的值来创建此哈希表?

2 个答案:

答案 0 :(得分:7)

一般性评论

  • 在函数中创建全局变量几乎总是错误的。

  • 使用read-from-string代替intern创建新符号几乎总是错误的。

使用宏

你可能想要的是

(defmacro def-ht (name)
  (let ((var (intern (concatenate 'string "*" (symbol-name name) "*")
                     (symbol-package name))))
    `(defparameter ,var (make-hash-table))))
(def-ht foo)

使用功能

您也可以在函数中执行此操作 - 检查macroexpansion表单的defparameter并将所需内容放入函数中:

(defun make-ht-var (name)
  (let ((var (intern (concatenate 'string "*" (symbol-name name) "*")
                     (symbol-package name))))
    (setf (symbol-value var) (make-hash-table))
    (proclaim (list var 'special))))
(make-ht-var 'foo)

请注意函数的参数是引用,但宏的参数是而不是

答案 1 :(得分:-1)

您需要使用宏而不是函数。 DEFPARAMETER会将MAKE-HASH-TABLE的值绑定到符号NAME,因为它会在比运行时更早的宏扩展时间内进行计算,这是函数FOO绑定NAME的词汇值时。

查看CL评估模型以获得更深入的理解。

(defmacro foo (arg)
  (let ((name (read-from-string (format nil "*~S*" arg))))
    `(defparameter ,name (make-hash-table)))) 

(foo "my-hash")
 => <hash-table 0x121>

*my-hash*
=> <hash-table 0x121>