Path: utzoo!mnetor!uunet!husc6!think!barmar From: barmar@think.COM (Barry Margolin) Newsgroups: comp.lang.lisp Subject: Re: Composition/Partapply in CL Question Message-ID: <13984@think.UUCP> Date: 18 Dec 87 21:40:11 GMT References: <1350002@otter.HP.COM> Sender: usenet@think.UUCP Reply-To: barmar@sauron.think.com.UUCP (Barry Margolin) Organization: Thinking Machines Corporation, Cambridge, MA Lines: 72 In article <1350002@otter.HP.COM> kers@otter.HP.COM (Christopher Dollin) writes: >Another question about doing things in CL! Even if your questions were silly (which they aren't), it's just such a refreshing break to see stuff in this newsgroup that isn't flames... > (defun compose (p q) > #'(lambda (&rest args) > (multiple-value-call q (apply p args)) > ) > ) > >is the obvious solution. Would implementors like to comment on its efficiency? That looks right to me. If you are willing to let COMPOSE be a macro instead of a function, then you could do: (defmacro compose (p q) `#'(lambda (&rest args) (apply ,q (multiple-value-list (apply ,p args))))) The only advantage this has is that it doesn't need to create a lexical closure to capture the local values of P and Q. However, this only conses a couple of words in the implementations I'm familiar with; in general, one needn't be afraid of returning lexical closures. > (Defun partapply (p &rest args) > #'(lambda (&rest more) > (apply p (append args more)) > ) > ) > >should work but it certainly doesn't LOOK efficient ... This one can definitely be made more efficient by being a macro, because then it doesn't have to do the APPEND at run time. (defmacro partapply (p &rest args) `#'(lambda (&rest more) (apply ,p ,@args more))) This isn't precisely correct, though, because it will evaluate the args at the time the resulting function is called rather than when partapply is called. For example (defun my-+ (a b) (let ((test-function (partapply #'+ a))) (setq a 0) (apply test-function b))) It's difficult to get it right, so your solution is probably what I would use. Symbolics has some code that tries to do something like the above right; their solution was to expand into a LET that binds all the free variables to their current values, and return a closure in that environment (they call this "snapshotting" the environment), but it has the problem that if the code modifies one of the snapshotted variables the change isn't seen outside the snapshot environment. (do ((i 1 (1+ i))) ((> i 10)) (snapshot-variables (setq i (1+ i)))) --- Barry Margolin Thinking Machines Corp. barmar@think.com seismo!think!barmar