[Small-cl-src-discuss] defun-with-cache (take 3)

Ben Hyde bhyde at pobox.com
Tue Dec 13 14:52:39 UTC 2005


On Dec 11, 2005, at 11:42 PM, Kristian Elof Sørensen wrote:
...
> ; It said (third-arg) here ???
...
> "call" is never referenced.

Thanks!

I have no idea why, but (declaim (optimize (sb-ext::inhibit-warnings  
3)))
was in my .sbclrc and no good can come of that.

Pretty soon this will get so simple it won't be small, it will be tiny.

  - ben


;;; -*- Lisp -*- mode

(cl:defpackage "DEFUN-WITH-CACHE"
     (:use "COMMON-LISP")
   (:export "DEFUN-WITH-CACHE" "CLEAR-CACHE-OF-FUNCTION"))

(in-package "DEFUN-WITH-CACHE")

(defun bindings-of-lambda-list (lambda-list)
   "Given a lambda list returns a list of the symbols it binds."
   (block nil
     (let ((binds nil))
       (flet ((accumulate (var) (push var binds))
	     (wrapup () (return (nreverse binds))))
	(dolist (elt lambda-list (wrapup))
	  (etypecase elt
	    (cons
	     (accumulate (first elt))
	     (when (third elt) (accumulate (third elt))))
	    (symbol
	     (case elt
	       ((&rest &optional &allow-other-keys &key))
	       (&aux (wrapup))
	       (otherwise (accumulate elt))))))))))

#|

(loop
     finally (return 'ok)
   for (in out) in '(((x y z) (x y z))
		    ((x y &optional z) (x y z))
		    ((x &optional (y 2 z)) (x y z))
		    ((x &optional (y 2)) (x y))
		    ((x &optional (y 2) &key z) (x y z)))
   do (assert (equal (bindings-of-lambda-list in) out)))

|#

(defmacro cache-of-function (function-name)
   "An equal hash table maybe stored on the plist of a function for  
caching."
   `(get ,function-name :cache-of-function))

(defun clear-cache-of-function (function-name)
   "Forget any cached results from invoking function of the given  
symbol."
   (clrhash (cache-of-function function-name)))

(defmacro defun-with-cache (name args &body body)
   "Like defun, but this memoizes the function into a cache that maybe
    latter cleared."
   (let ((binding (bindings-of-lambda-list args)))
     `(let ((#1=#:cache (make-hash-table :test #'equal)))
       (setf (cache-of-function ',name) #1#)
       (defun ,name ,args
	(let ((#2=#:key (list , at binding)))
	  (values-list
	   (or (gethash #2# #1#)
	       (setf (gethash #2# #1#)
		     (multiple-value-list
			 (progn , at body))))))))))







More information about the Small-cl-src-discuss mailing list