[Bese-devel] "Memoized" One time actions.

Drew Crampsie drewc at tech.coop
Fri Feb 4 09:10:39 UTC 2005


In the midst of the great "fight for continuations" that is being waged 
by the faithful on c.l.l, an infidel of unpure heart said :

 > Also, if I add an entry to the clipboard, then open a new window, the
 > same entry gets added again, once for each time that same URL gets
 > hit. It seems that these operations or "actions" are not
 > idempotent. Is that intentional?

And damnit, he was right. I don't know if UCW solves this problem, but 
it wasn't hard to implement, so i fought back:
-----

(defclass memoize-component ()
   ((memos :initarg :memos :accessor memos :initform (make-hash-table 
:test #'equalp)))
   (:metaclass standard-component-class))

(defaction run-memo ((m memoize-component) fun &rest args)
   (let* ((memo-id
       (concatenate 'string
                (ucw::find-session-id *context*)
                (ucw::find-frame-id *context*)
                (ucw::find-action-id *context*)))
      (memo (gethash memo-id (memos m))))
     (or memo
     (setf (gethash memo-id (memos m)) (apply fun args)))))

(defmacro defaction-memoize (name args &body body)
   (let ((fun (concatenate 'string
               (string name)
               "-"
               (string (gensym)))))
     `(progn
        (defaction ,(intern fun) ,args
      , at body)
        (defaction ,name ,args
      (run-memo ,(caar args) #',(intern fun) ,(caar args) ,@(cdr args))))))

with that done i just add the mixin to my SEARCH-BOX class, and use 
DEFACTION-MEMOIZE rather than DEFACTION for any destructive actions that 
manpulate global state:

(defaction-memoize add-to-clipboard ((search-box 
search-box-with-clipboard) item)
   (setf (clipboard search-box) (cons item (clipboard search-box))))

Which expands like to :

RR-GEO> (macroexpand-1 '(defaction-memoize add-to-clipboard ((search-box 
search-box-with-clipboard) item)
   (call 'info-message :message (ucw::find-action-id *context*))
   (setf (clipboard search-box) (cons item (clipboard search-box)))
))
(PROGN
  (DEFACTION ADD-TO-CLIPBOARD-G9697
             ((SEARCH-BOX SEARCH-BOX-WITH-CLIPBOARD) ITEM)
             (CALL 'INFO-MESSAGE
                   :MESSAGE
                   (IT.BESE.UCW::FIND-ACTION-ID *CONTEXT*))
             (SETF (CLIPBOARD SEARCH-BOX) (CONS ITEM (CLIPBOARD 
SEARCH-BOX))))
  (DEFACTION ADD-TO-CLIPBOARD
             ((SEARCH-BOX SEARCH-BOX-WITH-CLIPBOARD) ITEM)
             (RUN-MEMO SEARCH-BOX #'ADD-TO-CLIPBOARD-G9697 SEARCH-BOX 
ITEM)))
T

I had to create a named function because of the CPS transformer (my 
first vesion used a lambda, but didn't work with actions), but it's 
essentially Paul Grahams memoize macro, only keyed on a continuation id 
rather than the arguments. This way the action will can be called 
multiple times, just not from the exact same page.

-----

if it's desirable to have this as part of UCW proper, we could probably 
do it as a method combination keyword like :

(defaction foo :memoize ((self class)) '())

And there has to be a better solution than that named function :)

Also, dolph on IRC noticed a bug in my installation, the arenida backend 
  is returning NIL as the http status code. I hard coded it to 200 here, 
and that works fine, but is probably not desired. I don't know enough 
about the backend to continue.

drewc



More information about the bese-devel mailing list