home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!olivea!apple!cambridge.apple.com!kab
- From: kab (Kim Barrett)
- Newsgroups: comp.lang.lisp.mcl
- Subject: Re: Apply
- Message-ID: <9208121541.AA03146@cambridge.apple.com>
- Date: 12 Aug 92 16:42:51 GMT
- Sender: info-mcl-request@cambridge.apple.com
- Lines: 62
- Approved: comp.lang.lisp.mcl@Cambridge.Apple.C0M
- Full-Name: Kim Barrett
- Original-To: Denis R Howlett <drh@world.std.com>
- Original-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).
-