home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #18 / NN_1992_18.iso / spool / comp / lang / lisp / mcl / 1195 < prev    next >
Encoding:
Text File  |  1992-08-12  |  3.0 KB  |  80 lines

  1. Path: sparky!uunet!olivea!apple!apple!cambridge.apple.com!cassels@cambridge.apple.com
  2. From: cassels@cambridge.apple.com (Robert A. Cassels)
  3. Newsgroups: comp.lang.lisp.mcl
  4. Subject: Re: Apply
  5. Message-ID: <9208121600.AA03318@cambridge.apple.com>
  6. Date: 12 Aug 92 16:11:09 GMT
  7. Sender: info-mcl-request@cambridge.apple.com
  8. Lines: 66
  9. Approved: comp.lang.lisp.mcl@Cambridge.Apple.C0M
  10. Full-Name: Bob Cassels
  11. Original-To: Denis R Howlett <drh@world.std.com>,
  12.         MacLisp Info Line <info-macl@cambridge.apple.com>
  13.  
  14. >I too discovered that apply and funcall don't work for lambda lists any
  15. >more and was rather disheartened since a great deal of our user interface
  16. >code relies on constructing functions which are then attached to buttons.
  17. >
  18. >Much of this code is created with backquotes so that variables can be
  19. >insterted, a simple example might be:
  20. >
  21. >(defun make-menu-items (items)
  22. >  (let (menu-items)
  23. >    (dolist (item items)
  24. >      (push (make-instance ...
  25. >                           :attached-function
  26. >                           `(lambda (window)
  27. >                  (declare (ignore window))
  28. >                              (print ',item)))))))
  29. >
  30. >I know the code isn't quite right but you get the idea, each lambda
  31. >expression is created at run time.
  32. >
  33. >The solution I have adopted (but don't like) is to make the function
  34. >dispatcher more intelligent and do the following:
  35. >
  36. >;; attached-function & window are bound in preceding lines
  37. >  (funcall (if (listp attached-function)
  38. >              (eval `(function ,attached-function))
  39. >              attached-function)
  40. >           window)
  41. >
  42. >This allows my dispatcher to deal with all the things that funcall (and
  43. >apply used to deal with), but I always thought it was bad form to use eval
  44. >in the middle of code? ...
  45.  
  46. Your particular example doesn't need to use EVAL.  Just use closures.
  47.  
  48. (defun make-menu-items (items)
  49.   (let (menu-items)
  50.     (dolist (item items)
  51.       (push (make-instance ...
  52.                            :attached-function
  53.                            (let ((item item))
  54.                              #'(lambda (window)
  55.                                           (declare (ignore window))
  56.                                  (print item))))))))
  57.  
  58. The reason for the seemingly spurious binding of ITEM has to do with the
  59. fact that DOLIST does it's iteration by SETQ'ing the iteration variable. 
  60. An alternative, cleaner way to do this is:
  61.  
  62. (defun make-menu-items (items)
  63.   (let (menu-items)
  64.     (mapc #'(lambda (item)
  65.               (push (make-instance ...
  66.                        :attached-function
  67.                        #'(lambda (window)
  68.                                     (declare (ignore window))
  69.                            (print item)))))
  70.            items)))
  71.  
  72. See the discussion on pp. 115-118 of CLtL II for more information about
  73. closures.
  74.  
  75. You are right that you need EVAL or COMPILE to turn arbitrary list
  76. structure into an object which is FUNCTIONP (as required by APPLY). 
  77. Fortunately, you don't need that most of the time.  You'll find that
  78. closures cover most of what you need.  Thay are also much more time- and
  79. space-efficient than using list expressions.
  80.