Macros 动态定义setf扩展器
我试图定义一个宏,它将接受结构的名称、键和结构中哈希表的名称,并定义函数来访问和修改哈希表中键下的值Macros 动态定义setf扩展器,macros,common-lisp,symbols,dynamically-generated,setf,Macros,Common Lisp,Symbols,Dynamically Generated,Setf,我试图定义一个宏,它将接受结构的名称、键和结构中哈希表的名称,并定义函数来访问和修改哈希表中键下的值 (defmacro make-hash-accessor (struct-name key hash) (let ((key-accessor (gensym)) (hash-accessor (gensym))) `(let ((,key-accessor (accessor-name ,struct-name ,key)) (,hash-
(defmacro make-hash-accessor (struct-name key hash)
(let ((key-accessor (gensym))
(hash-accessor (gensym)))
`(let ((,key-accessor (accessor-name ,struct-name ,key))
(,hash-accessor (accessor-name ,struct-name ,hash)))
(setf (fdefinition ,key-accessor) ; reads
(lambda (instance)
(gethash ',key
(funcall ,hash-accessor instance))))
(setf (fdefinition '(setf ,key-accessor)) ; modifies
(lambda (instance to-value)
(setf (gethash ',key
(funcall ,hash-accessor instance))
to-value))))))
;; Returns the symbol that would be the name of an accessor for a struct's slot
(defmacro accessor-name (struct-name slot)
`(intern
(concatenate 'string (symbol-name ',struct-name) "-" (symbol-name ',slot))))
为了测试这一点,我有:
(defstruct tester
(hash (make-hash-table)))
(defvar too (make-tester))
(setf (gethash 'x (tester-hash too)) 3)
当我跑的时候
(make-hash-accessor tester x hash)
然后
它应该返回3t
,但是
(setf (tester-x too) 5)
给出了错误:
The function (COMMON-LISP:SETF COMMON-LISP-USER::TESTER-X) is undefined.
[Condition of type UNDEFINED-FUNCTION]
(宏扩展-1'(使哈希访问器测试仪x哈希))
扩展为
(LET ((#:G690 (ACCESSOR-NAME TESTER X)) (#:G691 (ACCESSOR-NAME TESTER HASH)))
(SETF (FDEFINITION #:G690)
(LAMBDA (INSTANCE) (GETHASH 'X (FUNCALL #:G691 INSTANCE))))
(SETF (FDEFINITION '(SETF #:G690))
(LAMBDA (INSTANCE TO-VALUE)
(SETF (GETHASH 'X (FUNCALL #:G691 INSTANCE)) TO-VALUE))))
T
我用的是SBCL。我做错了什么?您应该尽可能使用。
具体来说,这里不是针对访问者名称,而是针对您的访问者:
(定义散列访问器(结构名称键散列)
(flet)(混凝土符号(s1和s2)
(内部(连接“字符串(符号名称s1)”-“(符号名称s2()())))
(let((散列键(concat符号结构名称键))
(获取哈希(concat符号结构名称哈希)))
`(项目
(defun,散列键(实例)
(gethash',key(,get hash实例)))
(defun(setf,散列键)(到值实例)
(setf(gethash',key(,get hash instance))到value)
“,哈希键)))
(defstruct测试仪
(哈希(生成哈希表)))
(也是defvar(制造测试仪))
(setf(gethash'x(测试仪哈希也是))3)
也
==>#S(TESTER:HASH#S(HASH-TABLE:testfasthash-EQL(X.3)))
(定义哈希访问器测试仪x哈希)
==>测试仪-x
(测试仪-x也适用)
==> 7; T
(setf(测试仪-x也)5)
也
==>#S(测试者:HASH#S(HASH-TABLE:testfasthash-EQL(X.5)))
请注意,我对宏使用了一个更为传统的名称:因为它定义了accessorts,所以通常将其命名为define-…
(参见)。
make-…
通常用于返回对象的函数(参见)
另见
记住,无论是在缩进还是在命名变量、函数和宏时,样式都很重要。您应该尽可能使用。
具体来说,这里不是针对访问者名称,而是针对您的访问者:
(定义散列访问器(结构名称键散列)
(flet)(混凝土符号(s1和s2)
(内部(连接“字符串(符号名称s1)”-“(符号名称s2()())))
(let((散列键(concat符号结构名称键))
(获取哈希(concat符号结构名称哈希)))
`(项目
(defun,散列键(实例)
(gethash',key(,get hash实例)))
(defun(setf,散列键)(到值实例)
(setf(gethash',key(,get hash instance))到value)
“,哈希键)))
(defstruct测试仪
(哈希(生成哈希表)))
(也是defvar(制造测试仪))
(setf(gethash'x(测试仪哈希也是))3)
也
==>#S(TESTER:HASH#S(HASH-TABLE:testfasthash-EQL(X.3)))
(定义哈希访问器测试仪x哈希)
==>测试仪-x
(测试仪-x也适用)
==> 7; T
(setf(测试仪-x也)5)
也
==>#S(测试者:HASH#S(HASH-TABLE:testfasthash-EQL(X.5)))
请注意,我对宏使用了一个更为传统的名称:因为它定义了accessorts,所以通常将其命名为define-…
(参见)。
make-…
通常用于返回对象的函数(参见)
另见
请记住,无论是在缩进中还是在命名变量、函数和宏时,样式都很重要。命名宏可能更清晰,因为它是定义函数,而不是返回函数。也可以将ACCESSOR-NAME
移动到本地函数,这样就不必担心它在编译时可用了。@jkiiski:没错,我尝试使用OP的符号,但我会编辑。命名宏DEFINE-HASH-ACCESSOR
可能更清晰,因为它是定义函数,而不是返回它们。也可以将ACCESSOR-NAME
移动到本地函数,这样就不必担心它在编译时可用了。@jkiiski:你说得对,我试图使用OP的符号,但我会编辑它。
(LET ((#:G690 (ACCESSOR-NAME TESTER X)) (#:G691 (ACCESSOR-NAME TESTER HASH)))
(SETF (FDEFINITION #:G690)
(LAMBDA (INSTANCE) (GETHASH 'X (FUNCALL #:G691 INSTANCE))))
(SETF (FDEFINITION '(SETF #:G690))
(LAMBDA (INSTANCE TO-VALUE)
(SETF (GETHASH 'X (FUNCALL #:G691 INSTANCE)) TO-VALUE))))
T