home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!olivea!apple!apple!cambridge.apple.com!cassels@cambridge.apple.com
- From: cassels@cambridge.apple.com (Robert A. Cassels)
- Newsgroups: comp.lang.lisp.mcl
- Subject: Re: Apply
- Message-ID: <9208121600.AA03318@cambridge.apple.com>
- Date: 12 Aug 92 16:11:09 GMT
- Sender: info-mcl-request@cambridge.apple.com
- Lines: 66
- Approved: comp.lang.lisp.mcl@Cambridge.Apple.C0M
- Full-Name: Bob Cassels
- Original-To: Denis R Howlett <drh@world.std.com>,
- MacLisp Info Line <info-macl@cambridge.apple.com>
-
- >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? ...
-
- Your particular example doesn't need to use EVAL. Just use closures.
-
- (defun make-menu-items (items)
- (let (menu-items)
- (dolist (item items)
- (push (make-instance ...
- :attached-function
- (let ((item item))
- #'(lambda (window)
- (declare (ignore window))
- (print item))))))))
-
- The reason for the seemingly spurious binding of ITEM has to do with the
- fact that DOLIST does it's iteration by SETQ'ing the iteration variable.
- An alternative, cleaner way to do this is:
-
- (defun make-menu-items (items)
- (let (menu-items)
- (mapc #'(lambda (item)
- (push (make-instance ...
- :attached-function
- #'(lambda (window)
- (declare (ignore window))
- (print item)))))
- items)))
-
- See the discussion on pp. 115-118 of CLtL II for more information about
- closures.
-
- You are right that you need EVAL or COMPILE to turn arbitrary list
- structure into an object which is FUNCTIONP (as required by APPLY).
- Fortunately, you don't need that most of the time. You'll find that
- closures cover most of what you need. Thay are also much more time- and
- space-efficient than using list expressions.
-