11
11
vc-append hbl-append vl-append)
12
12
redex))
13
13
@(define redex-eval (make-base-eval '(require redex/reduction-semantics)))
14
+ @(define (mini-heading . whatever) (apply section whatever))
14
15
15
16
@title{Languages}
16
17
@@ -63,6 +64,8 @@ Non-terminals used in @racket[define-language] are not bound in
63
64
@pattech[side-condition] patterns and duplicates are not constrained
64
65
to be the same unless they have underscores in them.
65
66
67
+ @mini-heading{Binding Forms}
68
+
66
69
Typical languages provide a mechanism for the programmer to introduce new names
67
70
and give them meaning. The language forms used for this (such as Racket's @racket[let ]
68
71
and @racket[λ ]) are called @deftech{binding forms}.
@@ -128,6 +131,8 @@ in their names.
128
131
The @racket[#:refers-to ] declaration says that, in a @racket[λ ] term, the @racket[e] subterm has the name from
129
132
the @racket[x] subterm in scope.
130
133
134
+ @mini-heading{Multiple Variables in a Single Scope}
135
+
131
136
To generalize to the version of @racket[λ ] in @racket[_lc-lang], we need to cope with multiple
132
137
variables at once. And in order to do that, we must handle the situation where some of the
133
138
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
166
171
Because the @racket[_lc-bind+let] language does not require that all binders in its @racket[let ] form
167
172
be distinct from one another, the @tech{binding forms} specification must declare what happens when there is a conflict.
168
173
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.)
170
176
171
177
It is possible to have multiple uses of @racket[#:refers-to ] in a single binding specification. For example,
172
178
consider a language with a @racket[letrec ] form.
@@ -201,6 +207,8 @@ refer to the bound variables @racket[(shadow x ...)].
201
207
(λ (x) 5 ))
202
208
#:lang lc-bind+letrec)]
203
209
210
+ @mini-heading{Ellipses in Binding Forms}
211
+
204
212
Some care must be taken when writing binding specifications that match patterns with ellipses.
205
213
If a pattern symbol is matched underneath ellipses, it may only be mentioned under the same number of ellipses.
206
214
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
224
232
is restricted to be mentioned only underneath a single ellipsis. Therefore the body of the @racket[let-values ]
225
233
form must refer to @racket[(shadow (shadow x ... ) ... )] rather than @racket[(shadow x ... ... )].
226
234
235
+ @mini-heading{Compound Forms with Binders}
236
+
237
+
227
238
So far, the nonterminals mentioned in @racket[#:refers-to ] have always represented
228
239
individual atoms. If a non-atom is mentioned, and it does not have a binding specification,
229
240
or that specification lacks an @racket[#:exports ] clause, no names are brought into scope.
@@ -261,6 +272,102 @@ shows this behavior.
261
272
The use of the @racket[#:exports ] clause in the binding specification for @racket[_lc-bind+patterns]
262
273
allows the use of nested binding patterns seen in the example. More precisely, each @racket[p] may itself
263
274
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)]
264
371
}
265
372
266
373
@defidform[::=]{
0 commit comments