Re: [sawfish] Re: The dark corners of rep



On May 14, Timo Korvola wrote:
> Eli Barzilay <eli barzilay org> writes:
> > * Even worse, `defvar' does its magic in a way that shadows possible
> >   later definitions:
> >
> >     user> (defvar x 123)
> >     x
> >     user> (define x 1234)
> >     user> x
> >     123
> 
> That looks like a bug:
> user> (let ((x 1234)) x)
> 1234
> user> (let () (define x 1234) x)
> 123
> Those two should be equivalent.

My guess is that

  (let () (define x 1234) x)

gets flattened somehow to just (define x 1234), which doesn't work in
the same way I showed.  (And my guess is that this flattening is
intended to mimic lisp code, but it's not needed.)


> It seems to work if you don't use defvar:
> user> (define y 123)
> user> (let () (define y 1234) y)
> 1234

Righ -- but after you do the above you get the toplevel `y' set to
1234.


> It also works inside defines:
> user> (define (foo) (let () (define x 1234) x))
> user> (foo)
> 1234

That's why I said that it's similar to JavaScript -- `define' seems to
be done at the nearest function scope.  It's very confusing to deal
with in JavaScript, and even more in rep because you'd expect scheme
or lisp-like behavior.


> >   which is of course not needed, because you can do the usual
> >   thing in scheme:
> 
> Scheme also allows creating local bindings with define in the
> beginning of the body of a lambda or let.

Yes, two equivalent ways to define the counter example would be:

  (define count!
    (let ((counter 0))
      (lambda () ...)))

  (define count!
    (let ()
      (define counter 0)
      (lambda () ...)))


> >   which happens because `define' is actually more like Lisp's
> >   `defvar' and `defun' in that it has a global effect
> 
> Looks like another bug that only affects toplevel.  Inside defines
> define seems to create local definitions as expected.

Hmm, that *does* seem to be a correct analysis -- nested scopes inside
functions do behave as expected:

  user> (define (foo)
          (define x 1)
          (let () (define x 2) x)
          x)
  user> (foo)
  1

So this makes `rep' be like JavaScript for toplevel definitions
only...

Here are some more gems:

* These wouldn't work in Scheme:

    user> (define (foo)
            (define x 1)
            (define x 2)
            x)
    user> (foo)
    2
    user> (define (foo)
            (define x 1)
            (define x (+ x 1))
            x)
    user> (foo)
    2
    user> (define (foo)
            (define x (cons 1 x))
            x)
    user> (foo)
    (1)
    user> (letrec ((x x) (x 2)) x)
    2
    user> (letrec ((x (cons 1 x))) x)
    (1)

* I'm sure that some people will want to wave that away as doing
  something reasonable, but:

    user> (define (foo)
            (define x 1)
            x
            (define x 2)
            x)
    user> (foo)
    1
    ;; Why didn't that return 2?  Because the second define turned to
    ;; a global one:
    user> x
    2

  And of course the expression that gets assigned to the global is
  evaluated in the local context:

    user> (define (foo)
            (define x 1)
            x
            (define x (+ x 1))
            x)
    user> (foo)
    1
    user> x
    2

* rep does have `symbol-value', as used in lisps to access the global
  value of a symbol -- but in rep it returns the lexical value instead
  (which misses the whole point of this function):

    user> (define (foo)
            (define x 1)
            x
            (define x (+ x 1))
            (symbol-value 'x))
    user> (foo)
    1
    user> (symbol-value 'x)
    2

  This goes in line with the fact that `set' can actually be used to
  change locals.

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


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