首页 > 解决方案 > 以编程方式生成符号宏

问题描述

我有一个由两部分组成的数据结构:

  1. 将符号映射到索引的哈希表
  2. 包含数据的向量的向量

例如:

(defparameter *h* (make-hash-table))
(setf (gethash 'a *h*) 0)
(setf (gethash 'b *h*) 1)
(setf (gethash 'c *h*) 2)

(defparameter *v-of-v* #(#(1 2 3 4)       ;vector a
                         #(5 6 7 8)       ;vector b
                         #(9 10 11 12)))  ;vector c

我想定义一个符号宏来获取向量a而不通过哈希图。在 REPL:

(define-symbol-macro a (aref *v-of-v* 0))

工作正常:

* a
#(1 2 3 4)

但可能有很多命名向量,我不知道映射会提前是什么,所以我需要自动化这个过程:

(defun do-all-names ()
  (maphash #'(lambda (key index)
           (define-symbol-macro key (aref *v-of-v* index)))
       *h*))

但这无济于事。而且我尝试过的任何组合都没有,例如将所有名称设为宏、反引号/逗号模板等。我开始怀疑这是否与它define-symbol-macro本身无关。这似乎是一个很少使用的功能,On Lisp 只提到了两次。这里和其他地方都没有太多提及。在这种情况下,我使用的是 SBCL 2.1

有人有想法么?

标签: common-lisp

解决方案


您需要像上面那样在运行时执行此操作:

(defun do-all-names ()
  (maphash #'(lambda (key index)
               (eval `(define-symbol-macro ,key (aref *v-of-v* ,index)))
           *h*))

DEFINE-SYMBOL-MACRO是一个宏并且不会计算它的所有参数。因此,您需要为每个参数对生成一个新的宏形式并对其进行评估。

另一种方法,通常在编译时,是编写一个在顶层生成这些表单的宏:

(progn
  (define-symbol-macro a (aref *v-of-v* 0))
  (define-symbol-macro b (aref *v-of-v* 1))
  ; ....
  )

推荐阅读