Hey all,

When I started looking at incorporating Miles's
`lambda-with-constant-bindings', I realised there were a number of
places in the code where we've done things like:

  `(lambda (...)
     ...
     (switch-to-buffer ,(current-buffer)))

i.e. we're grabbing the values of arbitrary forms from the defining
environment, not just variables.  So, I've reworked Miles's macro a
little and have come up with something equally hairy that seems to do
the job:

  (defvar tla--gensym-counter 0)

  (defun tla--gensym (&optional arg)
    "Generate a new uninterned symbol.
    The name is made by appending a number to PREFIX, default \"tla\"."
    (let ((prefix (if (stringp arg) arg "tla"))
          (num (if (integerp arg) arg
                 (prog1
                     tla--gensym-counter
                   (setq tla--gensym-counter (1+ tla--gensym-counter))))))
      (make-symbol (format "%s%d" prefix num))))


  (defun tla--capturing-lambda-helper (l)
    (cond ((atom l) l)
          ((eq (car l) 'capture)
           (let ((g (tla--gensym)))
             (push (list g (cadr l)) captured-values)
             g))
          (t (mapcar 'tla--capturing-lambda-helper l))))


  (defmacro tla--capturing-lambda (args &rest body)
    "A `lambda' capable of capturing values from its defining environment.
    Values to be captured should be surrounded by (capture ...).
    For example:
  
      (let* ((y 'lexical-y)
             (l (tla--capturing-lambda ()
                  (list x (capture y)))))
        (let ((y 'dynamic-y)
              (x 'dynamic-x))
          (funcall l)))
  
    => (dynamic-x lexical-y)
    "
    (let ((captured-values '()))
      (let ((body (tla--capturing-lambda-helper body)))
        ``(lambda ,',args
            (let (,,@(mapcar (lambda (var) ``(,',(car var)
                                              ',,(cadr var)))
                             captured-values))
              (funcall ,(lambda () ,@body)))))))

So, the above would be written:

  (capturing-lambda (...)
    ...
    (switch-to-buffer (capture (current-buffer))))

I've tried this under Emacs and XEmacs and both seem to work correctly.
Does anyone have any thoughts on this?  Is this something that would
count as a bugfix against 0.9, or should I introduce this in a
development branch?

Cheers,

Mark

-- 
Mark Triggs
<[EMAIL PROTECTED]>

Reply via email to