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

variata



    Date: Thu 24 Apr 86 09:43:04-CST
    From: David Bartley <Bartley%ti-csl.csnet at CSNET-RELAY.ARPA>

    >Date: Wed, 23 Apr 86 23:13:58 EST
    >From: Jonathan A Rees <JAR%mc.lcs.mit.edu@CSNET-RELAY.ARPA>
    >Subject:  variata

    I'm in general agreement with JAR's proposals, but...

    >  - (ELSE) isn't a legal clause.  [If it is, what does it return, and why?]
    >  - (COND) and (CASE x) are syntactically legal expressions.  [No one
    >    objected to this liberalization when I raised the question before.]

    What is the difference between (COND (ELSE)) and (COND)?  Why is one
    wrong but the other OK?  

(COND (ELSE)) is the same as (COND (ELSE (BEGIN))), so it's OK iff
(BEGIN) is OK.  But we established that (BEGIN) isn't OK, because it's
not OK in the RRRS and several people have objected to its being OK.

(COND) is OK because because (COND (test expr)) and (COND (ELSE expr))
are both OK, and that's because I proposed that the syntax of COND be
  (COND <zero or more non-ELSE clauses> <optional ELSE clause>).
I don't really care about this, but I would rather NOT want to see the
syntax of COND be (COND <one or more clauses only the last of which can
be an ELSE clause>), which is what the RRRS says, because I think that's
somewhat inelegant.  An alternative, however, is to make the syntax be
 (COND <one or more non-ELSE clauses> <optional ELSE clause>).  I guess
that would be more compatible with IF.  So I want to give you the two
choices:
   (a) (COND) and (COND (ELSE foo)) are both necessarily legal (compatible
         with RRRS since it's more liberal).
   (b) (COND) and (COND (ELSE foo)) are both not necessarily legal
         (incompatible with RRRS in a way which I wouldn't expect people
	 to be too bothered about).
but not the choice (status quo):
   (c) (COND (ELSE foo)) is legal but (COND) isn't.
You've almost convinced me that (b) is the better choice than (a).  I
really don't care as much as the volume of my words would indicate, so
advise me.

I guess no one read my BNF carefully, or this would have been discussed
earlier.

    >  - (BEGIN) and (LAMBDA (X)) are not necessarily syntactically legal.
    >    [Several people objected to this extension.]

    What is the difference between (BEGIN) and (COND)?  Why is one wrong
    but the other OK?

(BEGIN) is not ok for reasons explained above.  I suggested that (COND)
be OK because it seemed consistent with (COND (ELSE exp)) already being
legal, but I think maybe you've convinced me that neither ought to be
necessarily legal.

    >  - It's not specified what happens if the constants in a CASE are
    >    objects other than numbers, symbols, characters, or booleans.
    >    [This allows implementations to decide for themselves what
    >    happens in other situations - EQV?, EQUAL?, etc.]

    I think CASE should continue to be defined in terms of EQV?.  This is
    consistent with Common LISP's CASE, which is defined in terms of EQL.
    There's also the issue of program-generated programs, which could
    conceivably have weird CASE keys (like closure objects) that are known
    to be EQ? or EQV? to other constants in the same procedure.  It's
    bizarre, but I'd like to know what to expect.

I don't think we don't disagree here.  If the keys are restricted to be
numbers, symbols, characters, or booleans, EQV? and EQUAL? will give
exactly the same result, so it doesn't matter at all which predicate the
manual decides to explain CASE in terms of; so I would leave the
description to be in terms of EQV?.  But observe that if it's not
specified what happens when there are constants other than numbers,
symbols, characters, or booleans, then the fact that the description is
in terms of EQV?  doesn't rule out implementations extending it to use
EQUAL?.

    >  - EQ? and EQV? must both return true if their arguments are both
    >    empty strings or both empty vectors. [...]

    What about those of us contemplating extending Scheme to include other
    compound types?  What happens with the following?

    	(EQ? (MAKE-VECTOR 0) (MAKE-ARRAY '(0)))

I would expect this to return false if either (a) the dimension of an
array can be changed dynamically or (b) VECTOR? never returns true of an
array or (c) there are procedures defined to work on arrays that aren't
defined to work on vectors.  My principles are: EQV? should implement
the operationally-indistinguishable relation as closely as possible, and
EQ?  should be as much like EQV? as possible given that it has to be
implementable as pointer comparison.

    	(EQ? (MAKE-VECTOR 0) (MAKE-ARRAY '(0 0)))

If there's a primitive like ARRAY-RANK or ARRAY-DIMENSIONS then these
are clearly distinct.

    	(EQ? (MAKE-ARRAY '(0 0)) (MAKE-ARRAY '(0 0)))

This probably depends on whether arrays are non-adjustable by default.
I forget whether or not they are.

    and my favorite,
    	(EQ? (MAKE-VECTOR 0 3) (MAKE-VECTOR 0 4))

What standard primitive could distinguish these?

The RRRS explains EQ? and EQV? in terms the notion of operational
equivalence; I'm just trying to make this idea precise.  I should
probably send out my proposed text in advance of the rest of the report,
since I think it manages to be simultaneously elegant, precise, and
compatible (except, apparently, with implementations which have multiple
empty strings & vectors).

If there's a way to operationally distinguish objects, they
aren't EQV?; if there isn't a way, I want the exceptions to be spelled
out plainly, with justifications.  Why should (EQV? '() '()) be true,
but not (EQV? "" "") or (EQV? '#() '#()) ?  What's the difference
between an empty list and an empty vector or empty string?  Or do you
want to allow there to be more than one empty list?

If operational equivalence must allow for all possible extensions to
Scheme, then it is a completely meaningless concept (e.g. numerically
equal numbers could be distinguishable from each other, if numbers had
property lists - whatever that means), and I'm at a loss for any other
way to explain EQV?.

    By the way, is (MAKE-VECTOR 0 <exp>) valid?  Is it reasonable to issue
    a warning message?

I think it's perfectly meaningful (see above), and there should be no
warning message.

    What if an implementation of Scheme extends it with adjustable arrays,
    as in Common LISP?

    	(LET ((X (MAKE-ARRAY '(0) :ADJUSTABLE 'T)))
    	  (EQ? X (MAKE-ARRAY '(0))))

    [I'm not advocating Common LISP's messy syntax, just using it for clarity.]

Seems to me that since "essential" vectors are simple (non-adjustable,
etc.), an adjustable vector is a very different beast.  Empty simple
vectors can't be distinguished from each other (i.e.  there's only one),
but adjustable empty vectors have local state, so they can be.

If vectors can be adjustable, shouldn't lists be too?  (MAKE-LIST 0
:ADJUSTABLE T) could return an empty list whose length can be changed.
(Not a serious suggestion.)

    Common LISP says that strings are the same as simple vectors with
    elements of type STRING-CHAR.  Is the empty string "" EQV? to a
    non-simple vector with elements of type STRING-CHAR?  

Not if there's a predicate which will distinguish simple vectors from
non-simple ones; and in Common Lisp there is.

    These questions are particularly pertinent for those of implementing
    both Scheme and Common LISP in the same name space (or one on top of
    the other).

It's certainly easy enough to create unique empty strings and vectors
and make Scheme's MAKE-STRING and MAKE-VECTOR return them when
appropriate.  I don't know whether it would be acceptable for a Common
Lisp implementation to do this when creating non-adjustble vectors of
length zero (don't have CLtL handy, will check later).  The only other
time when these things are created out of Scheme's control is by the
reader, but -- as I've discovered by doing a Scheme in CL myself --
Scheme really wants its own reader anyhow, to deal with the number
syntax and with colon being a constituent character.

If people believe that it's important to be able to parse Scheme's read
syntax using only standard Common Lisp reader features, then by all
means we must allow (eq? '#() '#()) to be false, but we also have to
change the syntax of numbers, and make colon not be a constituent
character.  But Scheme's eqv? could still deal with #() and "" as I
propose even if eq? doesn't.

It looks like I'll lose on this point, so I won't push it too hard.  I'm
just resisting adding yet another clause which basically says "we did
this for compatibility with Common Lisp."  Sorry to stir up the muck
again.

    >The RRRS says nothing at all about whether the result of APPEND sharing
    >structure with its arguments.  Common Lisp says explicitly that all
    >arguments but the last are copied, and the last one never is.  I think
    >this is wrong, and maybe incompatible with existing implementations.  T
    >permits sharing (not clobbering) whenever that makes sense, e.g.
    >      (let ((x (list 1 2)))
    >	     (eq? x (cdr (append '(a) x '() '()))))
    >might be true.  Is it OK if I make this explicitly OK?

    I'd like some discussion on this.  It sounds like something a LISP
    programmer could trip up on, especially those who use (APPEND X '())
    to copy X.  Steele's book specifically mentions that APPEND will work
    that way in Common LISP, but implies that it is poor style.  My
    inclination is to be compatible with Common LISP in order to minimize
    frustration for the poor people we're trying to win over to Scheme.

If this is what other people want I'm happy with it too (except again
for the fact that I'll have to insert another apology and another
reference to Common Lisp).

    >What about (let ((x (list 'a))) (eq? x (reverse x))) ?

    I feel strongly that REVERSE should always copy (unless its argument
    is the empty list), since it is easier to remember that rule than that
    it does so only when there's more than one element in the list.
    Pragmatically, I often do something like (APPEND! (REVERSE X) Y), and
    wouldn't want to side effect the original list in X if it had exactly
    one element.  (Note that this works correctly when X is the empty
    list, so this is a pretty unusual boundary condition.)

I agree.  (Except note that it doesn't copy empty lists....)

Jonathan