[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
   `let1'.

 * 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.

Matthew



Posted on the users mailing list.