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

Reply via email to