[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Apply



>I too discovered that apply and funcall don't work for lambda lists any
>more and was rather disheartened since a great deal of our user interface
>code relies on constructing functions which are then attached to buttons.
>
>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? ...

It IS bad form to use EVAL. You should realize that by saying
(apply '(lambda (...) ...) ...), you were implicitly calling EVAL
(or COMPILE). Closures will often solve your problem:

(defun make-menu-items (items)
  (let (menu-items)
    (dolist (item items)
      (push (make-instance ...
              :attached-function
              #'(lambda (window)
                  (declare (ignore window))
                  (print item)))
            menu-items)
      ...)))

Then you can leave your dispatching code as (funcall attached-function window).