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

Re: [r6rs-discuss] [Scheme-reports] redefining eqv?

Three hours ago, Peter Kourzanov wrote:
> On Thu, 2010-12-23 at 20:39 -0500, Eli Barzilay wrote:
> > Earlier today, Peter Kourzanov wrote:
> > > On Wed, 2010-12-22 at 18:36 -0500, Eli Barzilay wrote:
> > > 
> > > > You're confusing (or mixing) a local binding (let ((eqv? ...)) ...)
> > > > with an implicit mutation (define eqv? ...).  
> > > 
> > > Is it?
> > 
> > ...an implicit muatation?  Yes.
> > ...so different?  Yes.
> > ...a confusion?  Thats how it seems.
> I don't agree. 

*sigh*...  This is a frustrating mis-discussion.  I said above that
you're confusing the two things, to which you replied with an obscure
"is it", so I answered three possible interpretation of that -- and
you continue with the vagueness: if you want to discuss something then
plase be more specific about what is it that you don't agree with.

> 11.2.1: "The first from of define binds <variable> to a new location
> before assigning the value of <expression> to it."  (other forms are
> trivially expressed using the first)
> That's exactly #1 (new location), #2 (setting the value) and #3
> (binding of the new location to the given name).  I can only relate
> #3 to the meaning of eqv? (the name) before (define eqv? ...).

The location that the text refers to is due to mutable variables in
Scheme.  It means that bindings map identifiers too (mutable)
locations rather than to values (which makes them all constant, as in
other functional languages like ML).  None of this happens when you
*re*define a binding -- that case turns into an implicit assignment in
R5RS (sans modules) but it is not intended to be a device that you'd
use instead of assignment, only as a way to reload code and getting
new values in effect for existing references.  It also doesn't happen
in R6RS where you just don't redefine bindings.

> > > The way I read R6RS, (define) is supposed to (#1) allocate a new
> > > location for this new eqv?, (#2) set! the result of the
> > > expression to it and (#3) mutate the *binding* for eqv? in the
> > > environment (or splice into parent environment when enclosed by
> > > begin). At least, that's what it typically does for other
> > > variables. I.e.,
> > 
> > That's r5rs w/out any module system.  Not r6rs (in a library).
> Is there a difference? Let's see...

Yes, there is a difference.  A toplevel `define' in R5RS is analogous
to a side-effect in a single ongoing repl, and in R6RS it is more like
an internal define, scoped by the library it is part of.

> 11.2: "Definitions may appear within a <top-level body> (section 8.1),
> at the top of a <library body> (section 7.1), or at the top of a <body>
> (section 11.3)."
> 8.1: "A <top-level body> is like a <library body> (see section 7.1),
> except that definitions and expressions may occur in any order."
> so => not this one,

(I have no idea what that "=>" stads for, what "this" refers to, and
what "not" negates.)

> > > And, BTW, 11.3 says that (define) is equivalent to (letrec*). So why
> > > are these cases so different then?
> > 
> > Because those are internal definitions.
> Again, what's the difference?

An internal block of `define's is equivalent to a `letrec' (or a
`letrec*' in R6RS), for example, this:

  (define x 1)
  (define x 2)

cannot appear in an internal definition context in the same way that
you cannot have two bindings for `x' in a `letrec'.  This behavior
makes these kinds of definitions very different than the kinds of
mutations you are trying to promote (the toplevel redefinition of

> Let's see...
> 7.1: "A <library body> is like a <body> (see section 11.3) except that a
> <library body>s need not include any expressions."
> so => not this one either,

(Still no clue why you quoted that, or what the conclusion is supposed
to be.)

> Finally:
> 11.3: "An expanded <body> (see chapter 10) containing variable
> definitions can always be converted into an equivalent letrec*
> expression."
> Chapter 10 goes into fine details of how to reorder according to
> 8.1.

(Or why the ordering of definitions is relevant.)

> > > I guess if R6RS enforced macro-implementation of (case), like
> > > Haskell's Prelude, the problem would be solved (via syntactic
> > > closures provided by hygiene & referential transparency of
> > > syntax-rules).
> > 
> > ??
> Let just prescribe the "wanted" syntax-rules implementation of case
> in the standard.  Then there can be no confusion about its meaning
> and no PhD required to understand what the standard intends but does
> not say.

(So far I see only one person who was confused over that.)

It's the nth time that you ask to specify that `case' be implemented
as a macro -- yet you haven't provided any motivation for doing so.

The only thing that looks close to a reason is your desire to be able
to customize the equality that it uses -- yet this doesn't require
forcing a macro implementation.  For example, the text could replace

  in the sense of `eqv?'


  in the sense of the current lexical binding for `eqv?'

and you get your kind of customization hook without a requirement on
the implementation.

As for the hook itself, there is first the question of why a hook is
needed, and then there's how it should be implemented.  The solution
of mutating `eqv?' is pretty horrible IMO -- and it's worse when you
actually want to do this by a `define'.  If anything, you should go
with advocating a plain `set!' which would clarify that you really
want some more "hook-ish" name like `current-equality', and better to
use some feature that avoids race conditions for threaded
implementations (eg, racket parameters).

That would be a much better suggestion, which I still won't like
because of situations like:

  ;; my code
  (define (foo x)
    ... case ...)

  ;; your code
  (define (bar x)
    (parameterize ([current-equality my-equal?])
      (case (foo x)
        [(1) (foo x)])))

In this case, the function I wrote breaks because you wanted to
customize your `case'.  Two outcomes of this are -- (a) you need to
use the customization very carefully, as in

  (define (bar x)
    (let ([x* (foo x)]
          [old-eq (current-equality)])
      (parameterize ([current-equality my-equal?])
        (case x*
          [(1) (parameterize ([current-equality old-eq])
                 (foo x))]))))

or (b) I write my `bar' in a defensive way and make sure that
`current-equality' is set to `eqv?', ending with similar hair.

Both of these seem much more unpleasant than passing in the equality
as an additional argument to some `case-with'.

          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!

r6rs-discuss mailing list