Vijay Lakshminarayanan writes: > On 6/23/06, Pascal Bourguignon <[EMAIL PROTECTED]> wrote: > > Then, you could just go back to lambda stuff: > > > > (shadow 'if) > > (defmacro if (test then else) > > `(funcall (cdr (assoc (not ,test) `((t . ,(lambda (x y) (funcall y))) > > (nil . ,(lambda (x y) (funcall > > x)))))) > > (lambda () ,then) (lambda () ,else))) > > This is just mind blowing. I never thought of using lambda's this way > even though I've read Paul Graham's implementation of Scheme's DELAY > and FORCE. > > However, considering that this is you, Pascal, I'm surprised that the > code generates a warning :-)
This is because I didn't compile that code. At the REPL, there's no problem because the shadow is executed before the defmacro. When you want to go thru the compiler, you need to instruct it to execute the shadow before the defmacro, with: (eval-when (:compile-toplevel :load-toplevel :execute) (shadow 'if)) > A question though, why didn't you just plug the THEN and ELSE forms > into the lambda like so: > > (shadow 'if) > (defmacro if (test then else) > `(funcall (cdr (assoc (not ,test) `((t . ,(lambda () ,then)) > (nil . ,(lambda () ,else))))))) > > Just a guess, but is it so that the compiler can optimize a template > of (lambda (x y) ...) whereas it cannot in this case? Indeed, it's perfectly possible to simplify it this way. I started with separate definitions of true and false functions, and I simply substitute their definition in the a-list, but we can indeed complete the simplification as you did. Now, there's a little problem. ASSOC, if not a primitive, uses IF. We'd really need to define true and false as functions. (defparameter true (lambda (then else) (funcall then))) (defparameter false (lambda (then else) (funcall else))) (defmacro if (test then else) `(funcall (not ,test) ,else ,then)) and have things set up to have effectively: (defconstant t true) (defconstant nil false) Which is difficult in Common Lisp, since the symbols T and NIL are defined to be bound to themselves: T --> T NIL --> NIL If we had a primitive like lambda-eq: (lambda-eq a b) if (eq a b) then returns (lambda (th el) th) else returns (lambda (th el) el) We could use a lambda-assoc: (defun lambda-assoc (key alist) (funcall (lambda-eq '() alist) (lambda () nil) (lambda () (funcall (lambda-eq key (caar alist)) (lambda () (car alist)) (lambda () (lambda-assoc key (cdr alist))))))) or directly write IF as: (defmacro if (test then else) `(funcall (lambda-eq nil (not ,test)) (lambda () ,else) (lambda () ,then))) So in conclusion, IF is a special operator in Common Lisp because we're at least one layer removed from pure lambda-calculus: Common Lisp is designed to be efficiently implemented on Von Neumann computers. -- __Pascal Bourguignon__ http://www.informatimago.com/ "Logiciels libres : nourris au code source sans farine animale." _______________________________________________ cl-faq mailing list cl-faq@lispniks.com http://www.lispniks.com/mailman/listinfo/cl-faq