On Mon, Nov 08, 2004 at 05:16:28PM +1100, Mark Triggs wrote:
> It's not so much about avoiding conflicts with the caller, as simulating
> some sort of lexical closure. The problem is that we want define a
> callback function (one of these lambdas) that retains values that were
> in scope when it was defined.
I see...
> Without the backquote, we'd have to arrange to make the value of `base'
> available by some other means. Run-time expansion of CL macros is
> something I'd not considered, but that should probably be fixed.
>
> Is there some easier way of doing this that we're missing?
Hmmm, you might consider using a backquoted wrapper only for binding, and
making the bulk of the lambda compilable, e.g., instead of:
(function-that-uses-lambda-later
`(lambda (args) (complicated code... ,variable)))
use:
(function-that-uses-lambda-later
`(lambda (args)
(let ((variable ,variable))
(funcall ,(lambda () (complicated code... variable))))))
You could even make a macro to do this, like:
(defmacro lambda-with-constant-bindings (constants args &rest body)
"Like `lambda', with constant bindings for variables in CONSTANTS.
Any references in BODY to a variable listed in CONSTANTS will evaulate
to the binding in effect when the lambda was created, rather than at
the time it is called."
``(lambda ,',args
(let (,,@(mapcar (lambda (var) ``(,',var ',,var)) constants))
(funcall ,(lambda () ,@body)))))
Here's an example of use:
(eval-when-compile (require 'cl))
(defvar test-var nil)
(defun test ()
(let ((a 0) (b 'x) (c 42))
(lambda-with-constant-bindings (a b c) (x y)
(setf test-var (list a b c x y)))))
If you compile this, and load it into a fresh-emacs, it seems to do the right
thing:
(funcall (test) 1 2)
=> (0 x 42 1 2)
[and `cl' still isn't loaded.]
-Miles
--
I'm beginning to think that life is just one long Yoko Ono album; no rhyme
or reason, just a lot of incoherent shrieks and then it's over. --Ian Wolff