Yeah! (And I think you're right about not having an implicit #%body, but I don't really know for sure.)
Robby On Wed, Jul 7, 2010 at 11:23 AM, Matthew Flatt <mfl...@cs.utah.edu> wrote: > Short version: > > I'm planning to change internal-definition expansion (anywhere that > says `body ...' in the Racket documentation) to allow expressions to > mingle with definitions. For example, > > (let () > (define (f) x) > (displayln f) > (define x 1) > (list f x)) > > would be allowed; the `displayln' call would print `#<procedure:f>', > and the result would be a list containing the function `f' and the > number 1. > > Some other changes related to internal-definitions have been suggested, > but I don't plan to implement them for now. > > ======================================== > > Long version: > > Mixing Expressions and Definitions > ---------------------------------- > > Long ago, internal-definition positions in MzScheme allowed multiple > sets of definitions separated by expressions. For example, > > (let () > (define x 1) > (display x) > (define y 2) > (display y)) > > was allowed. In that old mode, the definition of `y' started a new > group of definitions, so the right-hand side of `(define x ...)' could > not refer to `y'. In other words, the above was equivalent to > > (letrec ([x 1]) > (display x) > (letrec ([y 2]) > (display y))) > > I think this behavior mimicked Chez Scheme at the time, but I may be > mistaken. For whatever reason (I don't remember), we changed > internal-definition positions to now allow additional definitions after > an expression. Maybe it was to more closely match R5RS. > > > Meanwhile, `unit', `module', `class' and other forms evolved to allow > expressions mixed with definitions. Probably as a result, many have > suggested that internal definitions similarly allow expressions mixed > with definitions --- without the old grouping. In that case, the `let' > above would be equivalent to > > (letrec-values ([(x) 1] > [() (begin (display x) (values))] > [(y) 2]) > (display y)) > > This change seems like a good idea. Now that I've finally gotten around > to trying it out, I think we should go with it immediately. > > > Should an expression be required at the end? A `module', `unit', or > `class' body can consist of just definitions. Similarly, if an > internal-definition context ends with a definition, we could define the > result to be `(void)', which is what the `block' form does. > > I think it's better to require an expression at the end, partly on the > grounds that the internal-definition block is supposed to return a > value (unlike the body of `module', etc.) and partly to avoid making > forms like > > (define (f x) > x > (define (g y) > y)) > > legal when they are almost certainly mistakes. > > This change could be implemented in new `lambda', etc. bindings, but I > think existing forms in `racket' should change. Furthermore, to keep > things simple, the existing `scheme' forms --- most of which are the > same binding as the `racket' forms --- should also change. > > The change should not affect the `r5rs' language, and we should change > the `r6rs' language so that it doesn't inherit the more liberal > handling of internal-definition forms. > > There are no issues with backward-compatibility for existing `scheme' > and `racket' modules, as far as I can tell. The change would just > accept more modules. > > > More Internal-Definition Contexts > --------------------------------- > > Internal definitions could be allowed in more places, such as > > (define f > (define x 2) > x) > > In principle, where a single expression is expected, definitions could > be allowed to precede the expression. > > It's a tempting generalization, but probably too confusing. I think > it's better to use some form that groups definitions with an > expression: `(let () ....)', `(block ....)', or something like that. > > > An Implicit Internal-Definitions Form > ------------------------------------- > > Many forms --- including `lambda' `let', and the function-shorthand > variant of `define' --- support internal definitions. The handling of > internal definitions is currently tired to the form. > > An alternative would be to have those forms implicitly wrap a group of > internal-definition forms with `#%body', in much the same way that an > application form is converted to a use of `#%app'. Then, the treatment > of internal definitions could be independently configured through a > module import. For example, one module might use a `#%body' that > corresponds to the old handling of internal definitions, while another > module could import a `#%body' that corresponds to the new handling. > > Setting aside the backward-compatibility issues of adding an implicit > form, I think it turns out not to work as well as `#%app'. The problem > is that there's not a good place to get the lexical context to use for > the implicit `#%body'. We have many macros analogous to > > (define-syntax-rule (squawk body ...) > (begin > (displayln "squawk!") > (let () body ...))) > > If you take the lexical context from the parentheses that surround the > `let' form, then the `#%body' is drawn from the context of the `squawk' > definition, while the intent was more likely to get it from the use of > `squawk'. Meanwhile, the `body ...' sequence itself doesn't necessarily > have a lexical context (since it doesn't have a parenthesis, roughly), > and the sequence is recreated by the macro implementation anyway. > > This problem happens occasionally with `#%app'. When a use of > identifier macro expands in an application position, for example, the > implementor of the identifier macro usually should copy the lexical > context of the old application form to the expansion result. Such cases > are more rare than examples like `squawk', though. > > So, an implicit `#%body' form seems like a good idea in principle, but > it doesn't seem to work out well with our current syntax. I'm currently > inclined to not change Racket and to treat this as something to support > better the next time we define a core syntax, but I'm interested in > further discussion. > > _________________________________________________ > For list-related administrative tasks: > http://lists.racket-lang.org/listinfo/dev > _________________________________________________ For list-related administrative tasks: http://lists.racket-lang.org/listinfo/dev