;; (MEMOIZED form) memoizes the result of form from its first evaluation.
;; Use like this:
;; (defun secret-password (...) ....... (memoized (random 1000)) ......)
(eval-when (compile load eval)
(when (eval '(flet ((ltv () (load-time-value (cons nil nil)))) (eq (ltv) (ltv))))
(pushnew :eval-uses-compiler *features*)))
(defmacro memoized (form)
`(LET ((MEMORY
(IF #-eval-uses-compiler (EVAL-WHEN (EVAL) T) #+eval-uses-compiler NIL
',(cons nil nil)
;; Careful: Different expansions of MEMOIZED forms must yield
;; LOAD-TIME-VALUE forms that are not EQ, otherwise compile-file
;; will coalesce these LOAD-TIME-VALUE forms. Therefore here we
;; explicitly cons up the list and don't use backquote.
,(list 'LOAD-TIME-VALUE '(CONS NIL NIL)))))
(UNLESS (CAR MEMORY)
(SETF (CDR MEMORY) ,form)
(SETF (CAR MEMORY) T))
(CDR MEMORY)))
You should probably be using either DEFVAR, LOAD-TIME-VALUE, or fare-memoization:MEMOIZED-FUNCALL for local memoizations.
macro example