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

[Scheme-reports] Fwd: R7RS

---------- Forwarded message ----------
From: Gerald Jay Sussman <gjs@x>
Date: Sun, Apr 28, 2013 at 9:40 PM
Subject: R7RS
To: "Arthur A. Gleckler" <aag@x>
Cc: Alexey Radul <axofch@x>

I am pleased to find that that the Scheme R^7 report was well done.  I
like it!  I have carefully examined the draft and I will be happy to
endorse it.  But I have one serious objection.

I think that the required unspecification of the values of eqv? and eq?
on procedures is a very bad choice.

In particular the line

   (let ((p (lambda (x) x)))   ==> unspecified
     (eqv? p p))

is inconsistent with the intended meaning of eqv?.

This predicate is intended to be an equivalence predicate, as asserted
in the first paragraph of section 6.1.  Thus it must be reflexive,
symmetric, and transitive.  This line violates those properties in the
case of a substantive first-class object, a procedure.

In addition, eq? should also operate in such a way to provide
procedures with an invariant identity.  We certainly want a call to
counter, defined as

   (define (counter count)
     (lambda ()
       (set! count (+ 1 count))

to produce an object with an identity.  So that

   (define c1 (counter 0))
   (define c2 (counter 0))

   (eq? c1 c2) ==> #f
   (eq? c1 c1) ==> #t
   (eq? c2 c2) ==> #t

This requirement shows why the following lines are bad policy.

   (let ((p (lambda (x) x)))   ==> unspecified
     (eq? p p))

   (eq? car car)               ==> unspecified

Any argument of the form "Making eq? and eqv? unspecified for
procedures makes it easier for the compiler writer to optimize code."
are both irrelevant and inaccurate.  The purpose of this document is
to specify a language, not to make life easier for compiler writers.
There is no significant runtime cost for a procedure to have an
invariant identity.  The requirement for such an identity does not
inhibit optimizations that specialize a procedure for a particular
use.  And the extra effort that is required in a compiler to provide
an invariant identity for a procedure, when it is needed, is minimal.

Any argument of the form "Since we cannot, in general, determine the
equivalence of procedures, we should not define such an equivalence."
is also irrelevant.  These predicates are not intended to provide a
general equivalence for procedures -- indeed that cannot be done.  The
deep purpose of eq? is tightly tied up with side effects.  If eq? is
true of two items then if we mutate one the other changes.  Cons cells
can be changed by set-car! and set-cdr!.  Procedures can be changed by
modifying a variable that is free in their definitions, as in the
counters introduced above.  So procedures are mutable data; it is
appropriate to provide a test to determine if two aliases refer to the
same mutable data object.

Gerald Jay Sussman

In response to this;

  >It may be worth noting, however, that some implementations
  > already rewrite "car" in operator position as "primitive-car", a
  > non-object, and in operand position as "(lambda (x) (primitive-car x))".
  > We are basically just granting permission to do that.

This does not change my argument.  The use of primitive-car in the
operator position causes no problems with eq?.  The use in the operand
position only matters if each operand position has "(lambda (x)
(primitive-car x))" explicitly written in, rather than a global

    (define car (lambda (x) (primitive-car x)))

Certainly the compiler can use the primitive-car in the operator
position, if that is what is wanted, without requiring a new closure
to be made for each passing of the car procedure.

I can personally see no advantage to wrapping a lambda around each use
rather than having a global definition, but so be it.  I don't think
that it is appropriate to screw up the defining standard for a
language, violating the mathematical meaning of "equivalence
predicate", to accomodate a funny implementation strategy.

By the way, which implementation does this?  Why?
Scheme-reports mailing list