微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

以编程方式生成符号宏

如何解决以编程方式生成符号宏

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

  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

有人有什么想法吗?

解决方法

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

(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))
  ; ....
  )
,

我不太确定您所说的“我不知道提前映射会是什么”。

你可以这样做:

(macrolet ((define-accessors ()
             `(progn,@(loop for key being the hash-keys of *h*
                        collect
                        `(define-symbol-macro,(gethash key *h*)))))))
  (define-accessors))

如果您知道自己不需要全局访问权限,那么您可以这样做:

(defmacro with-named-vector-accessors (&body body) ; is that the name you want?
  `(symbol-macrolet (,@(loop for key being the hash-keys of *h*
                             collect `(,(gethash key *h*))))),@body))

;;; Example Usage:
(with-named-vector-accessors
  (list a b c)) ;=> (#(1 2 3 4) #(5 6 7 8) #(9 10 11 12))

还有,

  1. 如果您知道 *h* 以及每个符号在宏扩展时映射到的索引,则上述方法有效。

  2. 如果您在宏扩展时知道 *h*,但每个符号映射到的索引在宏扩展后会发生变化,您将需要收集 (,key (aref *v-of-v* (gethash,key *h*)))

PS:如果您发现 loop 对哈希表来说很难看,您可以使用 iterate 库的语法:

(iter (for (key value) in-hashtable *h*)
  (collect `(,value))))

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。