[plt-scheme] I'm not saying it's a bug, but I don't understand the behavior of this code

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Wed Nov 15 20:39:50 EST 2006

At Wed, 15 Nov 2006 17:24:22 -0600, Kyle Smith wrote:
> However, after some more playing with it I noticed that if the same code 
> were put inside a let statement, or an equivalent lambda as in this 
> example, the counter stutters  on the first number, repeating it twice.  
> Which I suppose means that somehow it has gone through an expansion once 
> without saving the state of count.  This is the part I don't 
> understand.  See example below.
> (module let1 mzscheme
>   ((lambda ()
>      (define-syntax let1
>        (let ([count 1])
>          (lambda (stx)
>            (define (inc!) (set! count (add1 count)))
>            (syntax-case stx ()
>              [(_ x v b)
>               (begin
>                 (printf "expanding ~a~n" count)
>                 (inc!)
>                 (syntax (let ([x v])
>                           (let ([x b]) (printf "~a~n" x) x))))]))))
>      (let1 x (let1 x (let1 x (let1 x 0 (add1 x)) (add1 x)) (add1 x)) 
> (add1 x))))
>   )
> (require let1)
> =>
> expanding 1
> expanding 1
> expanding 2
> expanding 3

This has to do with the conversion of internal definitions into
`letrec', etc.:

 * The expander for `lambda' starts expanding the body to find
   definitions. As long as it finds definitions, it will collect them
   to convert into a `letrec-values' or `letrec-syntaxes+values' form.

 * When the expander finds a syntax definition, it executes it, just in
   case the newly defined is used to generate more definition forms in
   the body. So that's the first instance of the transformer for

 * In this case, expanding the first uses of `let1' produces an
   expression (not a definition), so the body of the procedure is
   converted to `letrec-syntaxes+values', and then expansion continues.

 * Expansion of the `letrec-syntaxes+values' form executes the
   transformer expression for `let1' again. That's the second instance,
   and that's where your counter starts over at 1.

 * Finally, the body of the `letrec-syntaxes+values' form is expanded,
   including the three remaining using of `let1'.

I think we could avoid the intermediate `letrec-syntaxes+values'
creation, and thus avoid the extra evaluation of the transformer
expression. We'll have to consider this for the next round of changes
to the expander.


Posted on the users mailing list.