Skip to content

Commit 51ae121

Browse files
committed
add some section headings to the binding forms declarations and
try to explain #:...bind related to racket#101
1 parent db73181 commit 51ae121

File tree

1 file changed

+108
-1
lines changed

1 file changed

+108
-1
lines changed

redex-doc/redex/scribblings/ref/languages.scrbl

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
vc-append hbl-append vl-append)
1212
redex))
1313
@(define redex-eval (make-base-eval '(require redex/reduction-semantics)))
14+
@(define (mini-heading . whatever) (apply section whatever))
1415

1516
@title{Languages}
1617

@@ -63,6 +64,8 @@ Non-terminals used in @racket[define-language] are not bound in
6364
@pattech[side-condition] patterns and duplicates are not constrained
6465
to be the same unless they have underscores in them.
6566

67+
@mini-heading{Binding Forms}
68+
6669
Typical languages provide a mechanism for the programmer to introduce new names
6770
and give them meaning. The language forms used for this (such as Racket's @racket[let]
6871
and @racket[λ]) are called @deftech{binding forms}.
@@ -128,6 +131,8 @@ in their names.
128131
The @racket[#:refers-to] declaration says that, in a @racket[λ] term, the @racket[e] subterm has the name from
129132
the @racket[x] subterm in scope.
130133

134+
@mini-heading{Multiple Variables in a Single Scope}
135+
131136
To generalize to the version of @racket[λ] in @racket[_lc-lang], we need to cope with multiple
132137
variables at once. And in order to do that, we must handle the situation where some of the
133138
names are the same. Redex's binding support offers only one option for this, namely taking
@@ -166,7 +171,8 @@ The intuition behind the name of the @racket[shadow] form can be seen in the fol
166171
Because the @racket[_lc-bind+let] language does not require that all binders in its @racket[let] form
167172
be distinct from one another, the @tech{binding forms} specification must declare what happens when there is a conflict.
168173
The @racket[shadow] form specifies that duplicate binders will be shadowed by earlier binders in its list of
169-
arguments.
174+
arguments. (Of course, if we were interested in modelling Racket's @racket[let] form, we'd
175+
want that term to be malformed syntax.)
170176

171177
It is possible to have multiple uses of @racket[#:refers-to] in a single binding specification. For example,
172178
consider a language with a @racket[letrec] form.
@@ -201,6 +207,8 @@ refer to the bound variables @racket[(shadow x ...)].
201207
(λ (x) 5))
202208
#:lang lc-bind+letrec)]
203209

210+
@mini-heading{Ellipses in Binding Forms}
211+
204212
Some care must be taken when writing binding specifications that match patterns with ellipses.
205213
If a pattern symbol is matched underneath ellipses, it may only be mentioned under the same number of ellipses.
206214
Consider, for example, a language with Racket's @racket[let-values] binding form.
@@ -224,6 +232,9 @@ occurs only under a single ellipsis, thus when it is mentioned in a @racket[#:re
224232
is restricted to be mentioned only underneath a single ellipsis. Therefore the body of the @racket[let-values]
225233
form must refer to @racket[(shadow (shadow x ...) ...)] rather than @racket[(shadow x ... ...)].
226234

235+
@mini-heading{Compound Forms with Binders}
236+
237+
227238
So far, the nonterminals mentioned in @racket[#:refers-to] have always represented
228239
individual atoms. If a non-atom is mentioned, and it does not have a binding specification,
229240
or that specification lacks an @racket[#:exports] clause, no names are brought into scope.
@@ -261,6 +272,102 @@ shows this behavior.
261272
The use of the @racket[#:exports] clause in the binding specification for @racket[_lc-bind+patterns]
262273
allows the use of nested binding patterns seen in the example. More precisely, each @racket[p] may itself
263274
be a pattern that mentions any number of bound variables.
275+
276+
@mini-heading{Binding Repetitions}
277+
278+
In some situations, the @racket[#:exports] and
279+
@racket[#:refers-to] keywords are not sufficiently
280+
expressive to be able to describe the binding structure of
281+
different parts of a repeated sequence relate to each other.
282+
For example, consider the @racket[let*] form. Its shape is
283+
the same as @racket[let], namely
284+
@racket[(let* ([x e] ...) e)], but the binding structure is
285+
different.
286+
287+
In a @racket[let*] form, each variable is accessible to
288+
each of the @racket[e]s that follow it, with all of the
289+
variables available in the body (the final @racket[e]). With
290+
@racket[#:exports], we can build an expression form that has
291+
a structure like that, but we must write syntax that nests
292+
differently than @racket[let*].
293+
294+
@examples[#:label #f #:eval redex-eval #:no-result
295+
(define-language lc-bind+awkward-let*
296+
(e ::= (let*-awk c e) natural x (+ e ...))
297+
(x ::= variable-not-otherwise-mentioned)
298+
(c ::= (clause x e c) ())
299+
#:binding-forms
300+
(let*-awk c e #:refers-to c)
301+
(clause x e c #:refers-to x) #:exports (shadow x c))]
302+
303+
The @racket[let*-awk] form binds like Racket's @racket[let*], with
304+
each clause's variable being active for the subsequent ones, but
305+
the syntax is different with extra nesting inside the clauses:
306+
307+
@examples[#:label #f #:eval redex-eval
308+
(term (substitute (let*-awk (clause x y (clause y x ()))
309+
(+ x y z))
310+
x
311+
1)
312+
#:lang lc-bind+awkward-let*)
313+
(term (substitute (let*-awk (clause x y (clause y x ()))
314+
(+ x y z))
315+
y
316+
2)
317+
#:lang lc-bind+awkward-let*)]
318+
319+
In order to get the same syntax as Racket's @racket[let*],
320+
we need to use the @racket[#:...bind] binding pattern
321+
annotation. A @racket[#:...bind] can appear wherever a
322+
@racket[_...] might appear, and it has the same function,
323+
namely indicating a repetition of the preceding pattern. In
324+
addition, however it comes with three extra pieces that
325+
follow the @racket[#:...bind] form that describe how the
326+
binding structure inside the repetition is handled. The
327+
first part is a name that can be used by a
328+
@racket[#:refers-to] outside of the repetition to indicate
329+
all of the exported variables of the sequence. The middle
330+
piece indicates the variables from a specific repetition of
331+
the ellipsis are exported to all subsequent repetitions of
332+
the ellipsis. The last piece is a @racket[beta] that moves
333+
backwards through the sequence, indicating what is exported
334+
from the last repetition of the sequence to the one before,
335+
from the one before to the one before that, and then finally
336+
from the first one to the export of the entire sequence (as
337+
named by the identifier in the first position).
338+
339+
So, in this example, we use @racket[#:...bind] to express the
340+
scope of @racket[let*].
341+
342+
@examples[#:label #f #:eval redex-eval #:no-result
343+
(define-language lc-bind+let*
344+
(e ::= (let* ([x e] ...) e) natural x (+ e ...))
345+
(x ::= variable-not-otherwise-mentioned)
346+
#:binding-forms
347+
(let* ([x e] #:...bind (clauses x (shadow clauses x)))
348+
e_body #:refers-to clauses))]
349+
350+
It says that the name of the exported variables from the entire sequence
351+
is @racket[clauses], which means that all of the variable exported
352+
from the sequence in the second position of the @racket[let*] bind
353+
variables in the body (thanks to the last @racket[#:refers-to] in the
354+
example). The @racket[x] in the second position following the @racket[#:...bind]
355+
says that @racket[x] is in scope for each of the subsequent @racket[[x e]] elements of
356+
the sequence. The final @racket[(shadow clauses x)] says that the variables
357+
in a subsequent @racket[clauses] are exported by the current one, as well as @racket[x],
358+
which then is exported by the entire sequence.
359+
360+
@examples[#:label #f #:eval redex-eval
361+
(term (substitute (let* ([x y] [y x])
362+
(+ x y z))
363+
x
364+
1)
365+
#:lang λL.4)
366+
(term (substitute (let* ([x y] [y x])
367+
(+ x y z))
368+
y
369+
2)
370+
#:lang λL.4)]
264371
}
265372

266373
@defidform[::=]{

0 commit comments

Comments
 (0)