[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Apply
- To: Denis R Howlett <drh@world.std.com>
- Subject: Re: Apply
- From: kab (Kim Barrett)
- Date: Wed, 12 Aug 92 11:42:51 EST
- Cc: MacLisp Info Line <info-macl@cambridge.apple.com>
> Much of this code is created with backquotes so that variables can be
> insterted, a simple example might be:
>
> (defun make-menu-items (items)
> (let (menu-items)
> (dolist (item items)
> (push (make-instance ...
> :attached-function
> `(lambda (window)
> (declare (ignore window))
> (print ',item)))))))
>
> I know the code isn't quite right but you get the idea, each lambda
> expression is created at run time.
>
> The solution I have adopted (but don't like) is to make the function
> dispatcher more intelligent and do the following:
>
> ;; attached-function & window are bound in preceding lines
> (funcall (if (listp attached-function)
> (eval `(function ,attached-function))
> attached-function)
> window)
>
> This allows my dispatcher to deal with all the things that funcall (and
> apply used to deal with), but I always thought it was bad form to use eval
> in the middle of code? ...
Much better would be to flush that hacked up function dispatcher and instead
either use closures, i.e.
(defun make-menu-items (items)
(let (menu-items)
(dolist (item items)
(let ((closed-item item)) ; ensure new binding for each item
(push (make-instance ...
:attached-function #'(lambda (window)
(declare (ignore window))
(print closed-item)) ; close over item
...)
...
or if you *really* need to be computing a lambda-expression, do the coercion
once there rather than redoing it each time you try to invoke it. Also, the
"approved" way to do the coercion is
(COERCE lambda-expression 'FUNCTION)
(see CLtL2, p.65). One warning about this however; MCL2.0 final contains a
buggy compiler-macro for this particular use of coerce. I expect this will be
fixed in some future patch, and in the meantime you can do what I did to work
around the problem, i.e. use something like the following function
;; MCL2.0 compiler-macro for coerce to function is buggy, so declare
;; coerce notinline to inhibit the transformation.
(defun coerce-lambda-expression-to-function (lambda-expression)
(declare (notinline coerce))
(coerce lambda-expression 'function))
ps. The line "(let ((closed-item item)) ..." is needed because you don't (in
general) know whether dolist establishes a fresh binding for each iteration or
uses the same binding repeatedly (by setq'ing it for each iteration).