[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

#T, self-evaluation, and NULL-LIST =? FALSE.



    Date: 20 Nov 85 12:39:08 EST (Wed)
    From: <ram%YALE-RING at YALE.ARPA>

    However, note the following behavior:

       > (eq? (true) '#T)
       ()

This is consistent with the message I sent out; the value of T is only
guaranteed to be true.  It's not guaranteed to be any particular true
object, and programs shouldn't ever depend on any aspect of its value,
other than its trueness.  It just happens in version 2.8, the variable T
evaluates to the symbol T.  In 2.9 it evaluates to something else.

    What then is the purpose of #T?  I realize the difference between #T
    and (TRUE), but I guess I was trying to say that I didn't see the
    need for #T, given that we have (TRUE) (or T, if you prefer).  It
    just seemed like unnecessary syntax (shudder!) to me.

The purpose of the syntax #T is to give a way to write a true boolean
value as a component of a composite literal datum.  It's basically
documentary: it gives a way to say that some part of a datum should be
true, but it prevents someone reading the code from imagining that
there's something important about the value used other than its
trueness.

E.g.: one might write
   (define (dark? color)
     (cond ((assq color
		  '((brown . #t) (black . #t) (white . #f) (yellow . #f)))
	    => cdr)
	   (else (error "unknown color"))))

If "t" is used instead of "#t", the code works the same, but using "#t"
makes it just a little clearer what's going on.

                                          ... (it's bad enough that numbers
        self-evaluate; where does one draw the line?)...

    I disagree.  The value of 34 is 34, not ERROR.

Disagreement is fine.  I agree that it's convenient to be able to write
'34 instead of 34.  I just wanted to point out that something strange is
going on when things "self-evaluate," since it's not the case e.g. that
(CONS X Y) evaluates to the list (CONS X Y).  Applying Occam's razor
here would dictate that the extra feature of self-evaluation for certain
expressions is unnecessary, so the extra complication should be
eliminated.  Since T has this feature, the design of T is not consistent
with Occam's razor.

                                          ... (It would have helped
        if we had distinguished #F from () back in 1981 when we had a
	chance.)

    We all use the fact that the null list and the false object are the
    same while programming.  This isn't due to any theoretical confusion
    (any more than making use of (CAR '()) => () is); it just happens to
    be convenient sugar for something that occurs very often.  ...

It would also be convenient to define (1 V) to mean the same thing as
(VREF V 1); that would avoid code clutter.  There are some languages in
which nearly all programs are correct.  This makes for very concise
code, and simplifies implementations since no error system or debugging
facilities are needed.

Having the domains boolean and list intersect is as theoretically
confused as (CAR '()) => (), namely very.  You have to go to great
lengths in the documentation, implementation, and formal semantics to
cause these things to happen.  It certainly is well-defined (and you
could therefore say it's not confused), but it's not elegant.

I suppose it's a matter of taste.  When you design a language you decide
what the domains of various primitives should be, and what coercions are
allowable when.  In Snobol4 you can write "2" + "2" and get 4; in
Algol68 you can write "2" + "2" and get "22".  These are two of my
favorite languages, and both have many excellent features which avoid
code clutter.  But these days I prefer disjoint domains, even if
increased code clutter results.  In particular, I think boolean, list,
symbol, and number should all be disjoint domains.  Simplifications like
this make programs easier to understand and debug, and streamlines both
the description and the implementation of the language.