Ich versuche, ein Makro zu definieren, das den Namen einer Struktur, einen Schlüssel und den Namen einer Hashtabelle in der Struktur nimmt und Funktionen definiert, um auf den Wert unter dem Schlüssel zuzugreifen und ihn zu ändern Hash.Setf Expander dynamisch definieren
(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))))
Um dies zu testen, habe ich:
(defstruct tester
(hash (make-hash-table)))
(defvar too (make-tester))
(setf (gethash 'x (tester-hash too)) 3)
Als ich
(make-hash-accessor tester x hash)
dann
(tester-x too)
es laufen zurück 3 T
, wie es sollte, aber
(setf (tester-x too) 5)
gibt den Fehler:
The function (COMMON-LISP:SETF COMMON-LISP-USER::TESTER-X) is undefined.
[Condition of type UNDEFINED-FUNCTION]
(macroexpand-1 '(make-hash-accessor tester x hash))
zu
(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
ich SBCL bin mit. Was mache ich falsch?
Es könnte klarer sein, das Makro 'DEFINE-HASH-ACCESSOR' zu nennen, da es Funktionen definiert und nicht zurückgibt. Verschieben Sie 'ACCESSOR-NAME' möglicherweise auch in eine lokale Funktion, sodass Sie sich keine Sorgen machen müssen, dass sie zur Kompilierzeit verfügbar ist. – jkiiski
@jkiiski: Sie haben Recht, ich habe versucht, mit der OP-Notation zu bleiben, aber ich werde bearbeiten. – sds