From: Roy Leonard
Subject: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <918eee97.0408240915.191a745a@posting.google.com>
I was wondering why (if ...) is a special operator instead of a macro?

It seems relatively trivial to implement it as a macro:

(defmacro my-if (condition first-exp second-exp)
  (or (and condition
          (or first-exp T))
      second-exp))

Which responds wonderfully to:
(my-if T (format T "yes") (format t "no"))
and
(my-if nil (format T "yes") (format t "no"))

so why make it a special operator? Is it merely for performance reasons?

From: Matthew Danish
Subject: Re: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <20040824174024.GF8087@mapcar.org>
On Tue, Aug 24, 2004 at 10:15:44AM -0700, Roy Leonard wrote:
> I was wondering why (if ...) is a special operator instead of a macro?
> 
> It seems relatively trivial to implement it as a macro:
> 
> (defmacro my-if (condition first-exp second-exp)
>   (or (and condition
>           (or first-exp T))
>       second-exp))
> 
> Which responds wonderfully to:
> (my-if T (format T "yes") (format t "no"))
> and
> (my-if nil (format T "yes") (format t "no"))
> 
> so why make it a special operator? Is it merely for performance reasons?

Probably because AND and OR are not special operators themselves?
See Figure 3-2 in chapter 3.1.2.1.2.1 Special Forms.

(defmacro my-and (&rest exprs)
  (cond ((null exprs)
	 t)
	((null (rest exprs))
	 (first exprs))
	(t
	 (let ((v (gensym)))
	   `(let ((,v ,(first exprs)))
	      (if ,v (my-and ,@(rest exprs))))))))

(defmacro my-or (&rest exprs)
  (cond ((null exprs)
	 nil)
	((null (rest exprs))
	 (first exprs))
	(t
	 (let ((v (gensym)))
	   `(let ((,v ,(first exprs)))
	      (if ,v ,v (my-or ,@(rest exprs))))))))

(defmacro my-cond (&rest exprs)
  (when exprs
    `(if ,(first (first exprs))
       (progn ,@(rest (first exprs)))
       (my-cond ,@(rest exprs)))))

Maybe you were using CLISP?  CLISP seems to report T for
(special-operator-p 'cl:and) and (special-operator-p 'cl:or).  I think
that this behavior is incorrect per the spec, since the description for
SPECIAL-OPERATOR-P says ``Returns /true/ if symbol is a /special
operator/;'' and /special operator/ is defined in the glossary to be
``one of a fixed set of symbols, enumerated in Figure 3-2.''  Neither
AND nor OR appear in that figure.  This is CLISP 2.30, though, a bit
old.

-- 
;;;; Matthew Danish -- user: mrd domain: cmu.edu
;;;; OpenPGP public key: C24B6010 on keyring.debian.org
From: Peter Seibel
Subject: Re: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <m3smacpg9d.fsf@javamonkey.com>
Matthew Danish <·······@andrew.cmu.edu> writes:

> Maybe you were using CLISP? CLISP seems to report T for
> (special-operator-p 'cl:and) and (special-operator-p 'cl:or). I
> think that this behavior is incorrect per the spec, since the
> description for SPECIAL-OPERATOR-P says ``Returns /true/ if symbol
> is a /special operator/;'' and /special operator/ is defined in the
> glossary to be ``one of a fixed set of symbols, enumerated in Figure
> 3-2.'' Neither AND nor OR appear in that figure. This is CLISP 2.30,
> though, a bit old.

From 3.1.2.1.2.2:

  "An implementation is free to implement any macro operator as a
  special operator, but only if an equivalent definition of the macro
  is also provided."

However, I'm not sure what that does to SPECIAL-OPERATOR-P.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Matthew Danish
Subject: Re: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <20040824182248.GH8087@mapcar.org>
On Tue, Aug 24, 2004 at 06:02:35PM +0000, Peter Seibel wrote:
> From 3.1.2.1.2.2:
> 
>   "An implementation is free to implement any macro operator as a
>   special operator, but only if an equivalent definition of the macro
>   is also provided."

I see this as saying ``You are free to implement macro operators the
same way you do special operators if it is more convenient or efficient
(for example) to do so, but for the sake of preserving semantics you
need to also provide a macro definition.''

-- 
;;;; Matthew Danish -- user: mrd domain: cmu.edu
;;;; OpenPGP public key: C24B6010 on keyring.debian.org
From: Peter Seibel
Subject: Re: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <m3wtzopgg4.fsf@javamonkey.com>
···········@gmail.com (Roy Leonard) writes:

> I was wondering why (if ...) is a special operator instead of a macro?
>
> It seems relatively trivial to implement it as a macro:
>
> (defmacro my-if (condition first-exp second-exp)
>   (or (and condition
>           (or first-exp T))
>       second-exp))

To start with, that's not right. A macro needs to return code, not run
it. You'd want something like this (note the backquotes and commas):

  (defmacro my-if (condition then-clause else-clause)
    `(or (and ,condition (or ,then-clause t)) ,else-clause))

> Which responds wonderfully to:
> (my-if T (format T "yes") (format t "no"))
> and
> (my-if nil (format T "yes") (format t "no"))

As you've written it, it only appears to work since you're testing it
at the REPL where macroexpansion is happening at the same time as
runtime. Try this:

  CL-USER> (defparameter *x* t)
  *X*
  CL-USER> (defun foo () (my-if *x* 'yes 'no))
  FOO
  CL-USER> (foo)
  YES
  CL-USER> (setq *x* nil)
  NIL
  CL-USER> (foo)
  YES ;;; oops!

> so why make it a special operator? Is it merely for performance reasons?

But to answer your real question try this:

  (macroexpand '(and x y))

or this:

  (macroexpand '(or x y))

The exact expansion will depend on your Lisp but they will probably
expand into something like this:

  (IF (NOT X) (PROGN NIL) (COND (T Y)))

and:

  (LET ((#:G4402 X)) (IF #:G4402 #:G4402 (COND (T Y))))

I.e. you have just implemented an IF-like construct on top of other
constructs are in turn built on top of IF. The language could have
been defined differently, make AND and OR special operators and then
defining IF in terms of them. Or COND could have been special and IF,
OR, and AND could have been written in terms of it. But you need one
special operator to express conditional evaluation and in Common Lisp
IF is it[1]. Historically COND was the special operator rather than IF
but I always thought it was sort of nice to have IF be it--it is after
all the essence of conditional execution--evaluate the condition, then
do this or do that.

-Peter

[1] Unless of course you want to go the functional route and have
distinguished "true" and "false" values which are themselves functions
in which case you can make IF a function:

  (defconstant +true+ #'(lambda (then else)
                          (declare (ignore else))
                          (funcall then)))

  (defconstant +false+ #'(lambda (then else)
                           (declare (ignore then))
                           (funcall else)))

  (defun if (test then else)
    (funcall condition then else))

Of course this doesn't really look like IF since all your test
expressions have to return either +true+ or +false+--no generalized
booleans--and you have to wrap all your clauses in lambda's:

  (if (test)
      #'(lambda () (do-whatever))
      #'(lambda () (do-some-other-thing)))

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Roy Leonard
Subject: Re: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <918eee97.0408241811.27643c4@posting.google.com>
Peter Seibel <·····@javamonkey.com> wrote in message
> As you've written it, it only appears to work since you're testing it
> at the REPL where macroexpansion is happening at the same time as
> runtime. Try this:
> 
> ...
I found that my code wouldn't even work if I:

CL-USER> (defparameter *y* nil)
*Y*

CL-USER> (my-if *y* 'yes 'no)
YES

Oops again.

I think this is actually the root of my error. I had remembered that
(my-if ...) wouldn't evaluate first-exp and second-exp, but I had
convienently forgotten that it would also not evaluate condition.

So

CL-USER> (my-if *y* 'yes 'no)

would be firstly evaluated to:

(or (and '*y*
         (or 'yes T))
    'no))

and, of course, since neither 'yes, nor '*y* is equal to nil/() (their
values notwithstanding), 'yes would be returned for any condition
other than 'literal' nil.

> I.e. you have just implemented an IF-like construct on top of other
> constructs are in turn built on top of IF. The language could have
> been defined differently, make AND and OR special operators and then
> defining IF in terms of them. 
> ...
For some reason I recall that computers in hardware "think" in terms
of and/or/etc. If this is true, wouldn't it make more sense to have
AND and OR and the like what other things are defined in, rather than
translating AND to IF then back to AND again?

Or is the little knowledge I have misleading me?


> [1] Unless of course you want to go the functional route and have
> distinguished "true" and "false" values which are themselves functions
> in which case you can make IF a function:

Yikes. I can understand how that works... but that is some freaky
code. *grin*
From: Svein Ove Aas
Subject: Re: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <cghecf$ca$1@services.kq.no>
Roy Leonard wrote:

> For some reason I recall that computers in hardware "think" in terms
> of and/or/etc. If this is true, wouldn't it make more sense to have
> AND and OR and the like what other things are defined in, rather than
> translating AND to IF then back to AND again?
> 
> Or is the little knowledge I have misleading me?
>
You're being mislead.
Computers do indeed have and, or and usually a few other logical operators
inbuilt; however, they don't implement conditional execution. They're
usually called "bitwise operators", and they are used for boolean
algebra.

The basic conditional statement is an arithmetic if; it can test a value
for something, and jump off if the test is true. (Or false, in some
cases.)

I'm not sure that this matches anything in CL very well, but (if) is
probably the closest.
From: Pascal Bourguignon
Subject: Re: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <87wtzmwtj8.fsf@thalassa.informatimago.com>
···········@gmail.com (Roy Leonard) writes:
> Peter Seibel <·····@javamonkey.com> wrote in message
> > I.e. you have just implemented an IF-like construct on top of other
> > constructs are in turn built on top of IF. The language could have
> > been defined differently, make AND and OR special operators and then
> > defining IF in terms of them. 
> > ...
> For some reason I recall that computers in hardware "think" in terms
> of and/or/etc. If this is true, wouldn't it make more sense to have
> AND and OR and the like what other things are defined in, rather than
> translating AND to IF then back to AND again?
> 
> Or is the little knowledge I have misleading me?

Probably.  The point of a high level language is to get as far as
possible from the hardware.  Let the hardware think in bits and AND or OR,
and keep thinking with lists of symbols in your mind and lisp.
 

> > [1] Unless of course you want to go the functional route and have
> > distinguished "true" and "false" values which are themselves functions
> > in which case you can make IF a function:
> 
> Yikes. I can understand how that works... but that is some freaky
> code. *grin*

That's the way it's done in Smalltalk.  
Is Smalltalk freaky?  It was designed for children...

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we.
From: Roy Leonard
Subject: Re: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <918eee97.0408241845.494d6c9@posting.google.com>
Peter Seibel <·····@javamonkey.com> wrote in message 
> As you've written it, it only appears to work since you're testing it
> at the REPL where macroexpansion is happening at the same time as
> runtime. Try this:
> 
>   CL-USER> (defparameter *x* t)
>   *X*
>   CL-USER> (defun foo () (my-if *x* 'yes 'no))
>   FOO
>   CL-USER> (foo)
>   YES
>   CL-USER> (setq *x* nil)
>   NIL
>   CL-USER> (foo)
>   YES ;;; oops!

Actually, I just figured out why you defun'd foo there.

I redefined my-if as:

CL-USER> (defparameter *y* nil)
*Y*

CL-USER> (defmacro 2-if (first-exp second-exp)
           (or (and *y*
                    (or first-exp T))
               second-exp))
2-IF

so it would take the value of *y*, instead of the symbol *y*.

Then:

CL-USER> (defun foo ()
           (2-if 'yes 'no))
FOO

CL-USER> (foo)
NO

CL-USER> (setf *y* T)
T

CL-USER> (foo)
NO

CL-USER> (2-if 'yes 'no)
YES


So, I figure FOO compiled (?) to:

(defun foo ()
  'NO)

because that's what was returned by 2-IF at compile-time.

if I call it, however, I still get:

CL-USER> #'foo
#'(LAMBDA NIL (DECLARE (LAMBDA-NAME FOO)) (BLOCK FOO (2-IF (QUOTE YES)
(QUOTE NO))))

so I assume there must be more than one internal representation of FOO
in the system - there's what I originally told it FOO was, and what
FOO compiled to.
From: Thomas A. Russ
Subject: Re: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <ymir7pvcbb6.fsf@sevak.isi.edu>
Peter Seibel <·····@javamonkey.com> writes:

> 
> ···········@gmail.com (Roy Leonard) writes:
> 
> > I was wondering why (if ...) is a special operator instead of a macro?
> >
> > It seems relatively trivial to implement it as a macro:
> >
> > (defmacro my-if (condition first-exp second-exp)
> >   (or (and condition
> >           (or first-exp T))
> >       second-exp))

But this isn't the correct translation of my-if, since first of all it
has the problems Peter Seibel notes:

> To start with, that's not right. A macro needs to return code, not run
> it. You'd want something like this (note the backquotes and commas):
> 
>   (defmacro my-if (condition then-clause else-clause)
>     `(or (and ,condition (or ,then-clause t)) ,else-clause))

This is closer, but it preserves a semantic flaw of the original code,
in that the return value of the IF is not correct.  If the test of the
if is true, then the value of the then clause must be returned, even if
the then clause evaluates to NIL.  That doesn't happen with the
formulation of given here.

  (my-if <anything> NIL T)

will always return T, whereas it should return NIL if <anything>
evaluates to be non-nil.  The real problem is the AND/OR tree can't
really handle properly the conditional nature of the computation
while preserving only single evaluation of the condition.

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Peter Seibel
Subject: Re: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <m3d61fncwx.fsf@javamonkey.com>
···@sevak.isi.edu (Thomas A. Russ) writes:

> Peter Seibel <·····@javamonkey.com> writes:
>
>> 
>> ···········@gmail.com (Roy Leonard) writes:
>> 
>> > I was wondering why (if ...) is a special operator instead of a macro?
>> >
>> > It seems relatively trivial to implement it as a macro:
>> >
>> > (defmacro my-if (condition first-exp second-exp)
>> >   (or (and condition
>> >           (or first-exp T))
>> >       second-exp))
>
> But this isn't the correct translation of my-if, since first of all it
> has the problems Peter Seibel notes:
>
>> To start with, that's not right. A macro needs to return code, not run
>> it. You'd want something like this (note the backquotes and commas):
>> 
>>   (defmacro my-if (condition then-clause else-clause)
>>     `(or (and ,condition (or ,then-clause t)) ,else-clause))
>
> This is closer, but it preserves a semantic flaw of the original
> code, in that the return value of the IF is not correct. If the test
> of the if is true, then the value of the then clause must be
> returned, even if the then clause evaluates to NIL. That doesn't
> happen with the formulation of given here.

Yup. I even thought about that issue for about thirty seconds when I
wrote my version but mistakenly convinced myself it wasn't a problem,
missing the case where then-clause would evaluate to NIL.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Vassil Nikolov
Subject: Re: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <lzllg24q6h.fsf@janus.vassil.nikolov.names>
···@sevak.isi.edu (Thomas A. Russ) writes:

> [...]
> The real problem is the AND/OR tree can't
> really handle properly the conditional nature of the computation
> while preserving only single evaluation of the condition.


  Furthermore, did anybody mention that in the boolean world (of
  mapping {0, 1} to {0, 1}), {AND, OR} isn't a basis: {NOT, AND} is,
  as is {NOT, OR}, and as is {NAND} (and a few others).


  Otherwise, are we allowed to "cheat" by using RETURN:

  (defmacro my-if (test then-clause else-clause)
    (let ((block-name (gensym "my-if-block-")))
      `(block ,block-name
         (or (and ,test (return-from ,block-name ,then-clause))
             ,else-clause))))

  (multiple values be damned)?

  ---Vassil.


-- 
Vassil Nikolov <········@poboxes.com>

Hollerith's Law of Docstrings: Everything can be summarized in 72 bytes.
From: Jeff Caldwell
Subject: Re: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <Ix_Wc.2909$NC6.178@newsread1.mlpsca01.us.to.verio.net>
For more about the general topic, see Structure and Interpretation of
Computer Programs, page 25, Exercise 1.6, on page 25 or at

http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-10.html#%_sec_1.1

The exercise asks "why if needs to be provided as a special form".

Jeff Caldwell



"Roy Leonard" <···········@gmail.com> wrote in message
·································@posting.google.com...
> I was wondering why (if ...) is a special operator instead of a macro?
>
> It seems relatively trivial to implement it as a macro:
>
> (defmacro my-if (condition first-exp second-exp)
>   (or (and condition
>           (or first-exp T))
>       second-exp))
>
> Which responds wonderfully to:
> (my-if T (format T "yes") (format t "no"))
> and
> (my-if nil (format T "yes") (format t "no"))
>
> so why make it a special operator? Is it merely for performance reasons?
From: Mark McConnell
Subject: Re: Newbie Question: Why is (if ...) a special operator?
Date: 
Message-ID: <d3aed052.0408250524.382c7450@posting.google.com>
···········@gmail.com (Roy Leonard) wrote in message news:<····························@posting.google.com>...
> I was wondering why (if ...) is a special operator instead of a macro?
> 
> It seems relatively trivial to implement it as a macro:
> 
> (defmacro my-if (condition first-exp second-exp)
>   (or (and condition
>           (or first-exp T))
>       second-exp))
> 
> Which responds wonderfully to:
> (my-if T (format T "yes") (format t "no"))
> and
> (my-if nil (format T "yes") (format t "no"))
> 
> so why make it a special operator? Is it merely for performance reasons?

Other posters have discussed the main issues, but I think the T in the
third line is also wrong.

(let ((my-list '())
      (n 17))
  ;; Do computations that possibly push items onto my-list and
possibly
  ;; change n.  If n is still 17, return my-list; otherwise, return
  ;; n to signal trouble.
  (if (= n 17)
      my-list
    n))

With my-if instead of if in the case n=17, the return value is
(or '() t) => t, whereas it's supposed to be '().