racket/pkgs/racket-doc/scribblings/reference/splicing.scrbl
Matthew Flatt 99f29ce8ee repair for nexted splicing forms that define the same name
Nested splicing forms would lead to an "ambigious binding" error
when the nested forms bind the same name, such as in

 (splicing-let ([a 1])
   (splicing-let ([a 2])
     (define x a)))

The problem is that splicing is implemented by adding a scope to
everything in the form's body, but removing it back off the
identifiers of a definition (so the `x` above ends up with no new
scopes). Meanwhile, a splicing form expands to a set of definitions,
where the locally bound identifier keeps the extra scope (unlike
definitions from the body). A local identifier for a nested splicing
form would then keep the inner scope but lose the outer scope, while
a local identifier from the outer splicing form would keep the outer
scope but no have the inner one --- leading to ambiguity.

The solution in this commit is to annotate a local identifier for a
splicing form with a property that says "intended to be local", so the
nested definition will keep the scope for the outer splicing form as
well as the inner one. It's not clear that this is the right approach,
but it's the best idea I have for now.
2015-07-29 06:11:13 -06:00

88 lines
3.0 KiB
Racket

#lang scribble/doc
@(require "mz.rkt" (for-label racket/splicing racket/stxparam racket/local))
@(define splice-eval (make-base-eval))
@interaction-eval[#:eval splice-eval (require racket/splicing
racket/stxparam
(for-syntax racket/base))]
@title[#:tag "splicing"]{Local Binding with Splicing Body}
@note-lib-only[racket/splicing]
@deftogether[(
@defidform[splicing-let]
@defidform[splicing-letrec]
@defidform[splicing-let-values]
@defidform[splicing-letrec-values]
@defidform[splicing-let-syntax]
@defidform[splicing-letrec-syntax]
@defidform[splicing-let-syntaxes]
@defidform[splicing-letrec-syntaxes]
@defidform[splicing-letrec-syntaxes+values]
@defidform[splicing-local]
)]{
Like @racket[let], @racket[letrec], @racket[let-values],
@racket[letrec-values], @racket[let-syntax], @racket[letrec-syntax],
@racket[let-syntaxes], @racket[letrec-syntaxes],
@racket[letrec-syntaxes+values], and @racket[local], except that in a
definition context, the body forms are spliced into the enclosing
definition context (in the same way as for @racket[begin]).
@examples[
#:eval splice-eval
(splicing-let-syntax ([one (lambda (stx) #'1)])
(define o one))
o
one
]
When a splicing binding form occurs in a @tech{top-level context} or
@tech{module context}, its local bindings are treated similarly to
definitions. In particular, syntax bindings are
evaluated every time the module is @tech{visit}ed, instead of only
once during compilation as in @racket[let-syntax], etc.
@examples[
#:eval splice-eval
(splicing-letrec ([x bad]
[bad 1])
x)]
If a definition within a splicing form is intended to be local to the
splicing body, then the identifier should have a true value for the
@racket['definition-intended-as-local] @tech{syntax property}. For
example, @racket[splicing-let] itself adds the property to
locally-bound identifiers as it expands to a sequence of definitions,
so that nesting @racket[splicing-let] within a splicing form works as
expected (without any ambiguous bindings).}
@defidform[splicing-syntax-parameterize]{
Like @racket[syntax-parameterize], except that in a definition context, the body
forms are spliced into the enclosing definition context (in the same way as for
@racket[begin]). In a definition context, the body of
@racket[splicing-syntax-parameterize] can be empty.
Note that @tech{require transformers} and @tech{provide transformers} are not
affected by syntax parameterization. While all uses of @racket[require] and
@racket[provide] will be spliced into the enclosing context, derived import or
export specifications will expand as if they had not been inside of the
@racket[splicing-syntax-parameterize].
@examples[
#:eval splice-eval
(define-syntax-parameter place (lambda (stx) #'"Kansas"))
(define-syntax-rule (where) `(at ,(place)))
(where)
(splicing-syntax-parameterize ([place (lambda (stx) #'"Oz")])
(define here (where)))
here
]}
@; ----------------------------------------------------------------------
@close-eval[splice-eval]