This example is based on that in Complete example of a top-level dspec class.
Define a
computed-saved-value
object has a function to compute the value the first time:
(defstruct (computed-saved-value (:include saved-value))
function)
saved-value
objects are defined using def-computed-saved-value and stored on the plist of their name:
(defmacro def-computed-saved-value (name function)
`(dspec:def (def-computed-saved-value ,name)
(when (record-definition `(def-computed-saved-value ,',name)
(dspec:location))
(setf (get ',name 'saved-value)
(make-computed-saved-value :name ',name
:function ,function))
',name)))
Define a function to compute a
computed-saved-value
:
(defun ensure-saved-value-computed (name)
(let ((saved-value (find-saved-value name)))
(or (saved-value-value saved-value)
(setf (saved-value-value saved-value)
(funcall
(computed-saved-value-function saved-value))))))
Define a macro to access a
computed-saved-value
:
(defmacro computed-saved-value (name)
`(ensure-saved-value-computed ',name))
Define a dspec class for
def-computed-saved-value
dspecs:
(dspec:define-dspec-class def-computed-saved-value def-saved-value
"Defined computed saved values"
:definedp
#'(lambda (name)
;; Find any object that def-computed-saved-value recorded
(computed-saved-value-p (find-saved-value name)))
;; The :undefiner is inherited from the superspace.
:object-dspec
#'(lambda (obj)
;; Given a computed-saved-value object, we can reconstruct its dspec
(and (computed-saved-value-p obj)
`(def-computed-saved-value ,(saved-value-name obj)))))
For completeness, define a form parser that generates dspecs from forms:
(dspec:define-form-parser
(def-computed-saved-value
(:parser dspec:single-form-form-parser)))
Note: this form parser for
def-computed-saved-value
is not strictly necessary, because the implicit form parser will recognize definitions beginning with "def".