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

  1. Path: sparky!uunet!olivea!apple!cambridge.apple.com!kab
  2. From: kab (Kim Barrett)
  3. Newsgroups: comp.lang.lisp.mcl
  4. Subject: Re: Apply
  5. Message-ID: <9208121541.AA03146@cambridge.apple.com>
  6. Date: 12 Aug 92 16:42:51 GMT
  7. Sender: info-mcl-request@cambridge.apple.com
  8. Lines: 62
  9. Approved: comp.lang.lisp.mcl@Cambridge.Apple.C0M
  10. Full-Name: Kim Barrett
  11. Original-To: Denis R Howlett <drh@world.std.com>
  12. Original-Cc: MacLisp Info Line <info-macl@cambridge.apple.com>
  13.  
  14. > Much of this code is created with backquotes so that variables can be
  15. > insterted, a simple example might be:
  16. > (defun make-menu-items (items)
  17. >   (let (menu-items)
  18. >     (dolist (item items)
  19. >       (push (make-instance ...
  20. >                            :attached-function
  21. >                            `(lambda (window)
  22. >                           (declare (ignore window))
  23. >                               (print ',item)))))))
  24. > I know the code isn't quite right but you get the idea, each lambda
  25. > expression is created at run time.
  26. > The solution I have adopted (but don't like) is to make the function
  27. > dispatcher more intelligent and do the following:
  28. > ;; attached-function & window are bound in preceding lines
  29. >   (funcall (if (listp attached-function)
  30. >               (eval `(function ,attached-function))
  31. >               attached-function)
  32. >            window)
  33. > This allows my dispatcher to deal with all the things that funcall (and
  34. > apply used to deal with), but I always thought it was bad form to use eval
  35. > in the middle of code? ...
  36.  
  37. Much better would be to flush that hacked up function dispatcher and instead 
  38. either use closures, i.e.
  39.  
  40.   (defun make-menu-items (items)
  41.     (let (menu-items)
  42.       (dolist (item items)
  43.         (let ((closed-item item))      ; ensure new binding for each item
  44.           (push (make-instance ...
  45.                   :attached-function #'(lambda (window)
  46.                                          (declare (ignore window))
  47.                                          (print closed-item)) ; close over item
  48.                   ...)
  49.                 ...
  50.  
  51. or if you *really* need to be computing a lambda-expression, do the coercion 
  52. once there rather than redoing it each time you try to invoke it.  Also, the 
  53. "approved" way to do the coercion is
  54.  
  55.   (COERCE lambda-expression 'FUNCTION)
  56.  
  57. (see CLtL2, p.65).  One warning about this however; MCL2.0 final contains a 
  58. buggy compiler-macro for this particular use of coerce.  I expect this will be 
  59. fixed in some future patch, and in the meantime you can do what I did to work 
  60. around the problem, i.e. use something like the following function
  61.  
  62.   ;; MCL2.0 compiler-macro for coerce to function is buggy, so declare
  63.   ;; coerce notinline to inhibit the transformation.
  64.   (defun coerce-lambda-expression-to-function (lambda-expression)
  65.     (declare (notinline coerce))
  66.     (coerce lambda-expression 'function))
  67.  
  68. ps. The line "(let ((closed-item item)) ..." is needed because you don't (in 
  69. general) know whether dolist establishes a fresh binding for each iteration or 
  70. uses the same binding repeatedly (by setq'ing it for each iteration).
  71.