Stephen Chang <stchang at racket-lang dot org>
and Alexander Knauth <alexander at knauth dot org>
This library implements new Racket binding forms (ie, ~define , ~lambda , ~let , etc.) that support generic binding instances. A generic binding instance is a syntax object that implements an "interface" (currently just some syntax properties) that the binding forms then use to determine how to proceed with the binding.
This moves the binding "logic" to the binding site itself and enables one binding form to support many different binding modes (ie, match or values ), rather than have to manually implement a version of each binding form for all the different combinations (ie, define-values , match-define , match-define-values , etc.).
The hope is that the forms in this library can be used in place of their analogous Racket counterparts.
The forms described in this section may be used only in binding positions of binding forms that support generic bindings. Any other use is invalid. For examples, see the next section, Core Generic Binding Forms.
bindings that may be used anywhere, and
bindings that may only be used in "define" contexts.
The second category is a subset of the first and is needed in order to handle Racket’s multiple return values . Since Racket functions cannot receive values , we must know what we are binding at the time of the binding. For example, this means that ~let may support values binding, but ~define or ~lambda may not. Thus, the second category essentially the first, but without values -bindings.
A few generic binding instances are currently supported. Defining new generic bindings is currently limited to new match -specific binding instances. See Implementing New Generic Binding Instances for more information.
syntax
( $ match-pattern)
Other generic binding instances can be nested within the match pattern.
syntax
( ~vs b...)
b = define-allowable-generic-binding
Currently supports one-level of nested generic binding instances. In other words, each binding site in the ~vs form may be either an identifier, or another generic binding instance. However, any nested binding positions are considered "define" contexts. This means that one cannot nest ~vs bindings.
syntax
( ⋈ b...)
syntax
( $: xxs)
syntax
( $stx patternpattern-directive...)
syntax
( $and b...)
b = generic-binding
syntax
( $c dbcontract-expr)
db = define-allowable-generic-bindingb = generic-binding
syntax
( ~define bbody)
b = generic-binding| identifier?db = define-allowable-generic-binding| identifier?
When using ~define to define a function, any generic binding must be define-allowable. (So the ~vs values-binding form is not allowed.)
> y110
> y220
> y320
> y430
> y540
> v1101
> v2202
> x499
> x5999
> x69999
> x7101
> y7202
#<syntax:eval:25:0 (#:a #:b #:c)>
#<syntax:eval:26:0 (1 2 3)>
#<syntax:eval:27:0 ((#:a . 1) (#:b . 2) (#:c . 3))>
> (f1100)110
> (f1100200)300
> (f1100200#:z300)600
> (f3123)'(1 2 3)
> (f3)'()
> (f4123456)'(1 2 3 4 5 6)
> (f412)'(1 2)
100
606
'(1 2 3)
'(1 2 3 4 5)
> (gg10001)10002
> (ggg5432)12345
> (gggg111)match-define: no matching clause for 111
> (gggg11111)22222
66
18
> (fkw1)13
40
> (fkw110)match-define: no matching clause for 10
13
40
> (fkw3#:B10)match-define: no matching clause for 10
syntax
( ~def ...)
syntax
( ~d ...)
syntax
( ~define/contract bcontract-exprbody)
b = generic-binding| identifier?db = define-allowable-generic-binding| identifier?
syntax
( ~lambda dbbody...)
db = define-allowable-generic-binding| identifier?
If a single identifier is given with no parentheses, then the arguments are put in a list, just like lambda . A single generic bind instance may also be used without parens. If a list of bindings if given, then each may be either an identifier or a generic bind instance.
syntax
( ~lam ...)
syntax
( ~l ...)
syntax
( ~λ ...)
111
'(1 2 3)
21
43
122
122
'(2 3 4 5 1)
'(2 2 3 4)
2
match-define: no matching clause for '(1 2 3)
10
100
eval:79:0: ~λ: expected a generic bind instance
at: ((~vs v1 v2))
in: (~λ ((~vs v1 v2)) (+ v1 v2))
parsing context:
while parsing a generic bind instance for define contexts
term: ((~vs v1 v2))
location: eval:79:0
22
24
'(2 3 1)
'(20 30 10)
'(2 3 1)
syntax
( ~case-lambda clause...)
clause = (headerbody...)
syntax
( ~case-lam clause...)
syntax
( ~case-define fclause1...)
clause1 = (headerbody...)clause2 = (b...→body...)
'()
'(2)
'(2 3)
'()
'()
'(2 4)
0
1
1
1
1
0
1
1
-1
-1
syntax
( ~case-def clause...)
'()
'(2)
'(2 3)
'()
'()
'(2 4)
0
1
1
1
1
0
1
1
-1
-1
syntax
( ~let loop([dbe]...)body...)
db = define-allowable-generic-bind| identifier?b = generic-bind| identifier?
Note that when using the match $ binding with ~let , the behavior is NOT like match-let , in that there is no coupling between between the binding positions. This means that trying to bind duplicate identifiers in a $ match pattern will produce the same results or errors as in let , let* , or letrec .
156
156
'(159 158)
44
57
eval:137:0: define-values: duplicate binding name
at: x
in: (define-values (x) (values g922))
eval:138:0: define-values: duplicate binding name
at: x
in: (define-values (x) (values g924))
eval:139:0: define-values: duplicate binding name
at: x
in: (define-values (x y) (let-local-keys ((g40402
stx-param929)) (let-values (((temp930) (values g928)))
(match*/derived (temp930) (match-define (list x y) (values
g928)) (((list x y)) (values x y))))))
eval:140:0: define-values: duplicate binding name
at: x
in: (define-values (x y) (let-local-keys ((g40402
stx-param935)) (let-values (((temp936) (values g932)))
(match*/derived (temp936) (match-define (list x y) (values
g932)) (((list x y)) (values x y))))))
eval:141:0: define-values: duplicate binding name
at: x
in: (define-values (x) g942)
2
12345
12345
5432
x59: undefined;
cannot reference an identifier before its definition
in module: top-level
f: undefined;
cannot reference an identifier before its definition
in module: top-level
20
eval:149:0: let: duplicate identifier
at: x
in: (let loop ((x 1) (x 2)) x)
eval:150:0: lambda: duplicate argument name
at: x
in: (lambda (x x) x)
109
109
syntax
( ~let* ([be]...)body...)
b = generic-bind| identifier?
46436
3030
9090
303
0
202
syntax
( ~letrec ([be]...)body...)
b = generic-bind| identifier?
x: undefined;
cannot use before initialization
3628800
> (factorial10)3628800
(evn?10))#t
(evn?10))#t
#t
#t
All the forms in this section are the same as their Racket counterparts (see for ), but with added generic bind support.
syntax
( ~for ...)
syntax
( ~for/list ...)
syntax
( ~for/lists ...)
syntax
( ~for/vector ...)
syntax
( ~for/fold ...)
syntax
( ~for/foldr ...)
syntax
( ~for/first ...)
syntax
( ~for/last ...)
syntax
( ~for/or ...)
syntax
( ~for/and ...)
syntax
( ~for/sum ...)
syntax
( ~for/product ...)
syntax
( ~for/hash ...)
syntax
( ~for/hasheq ...)
syntax
( ~for/hasheqv ...)
syntax
( ~for/hashalw ...)
syntax
( ~for* ...)
syntax
( ~for*/list ...)
syntax
( ~for*/lists ...)
syntax
( ~for*/vector ...)
syntax
( ~for*/fold ...)
syntax
( ~for*/foldr ...)
syntax
( ~for*/first ...)
syntax
( ~for*/last ...)
syntax
( ~for*/or ...)
syntax
( ~for*/and ...)
syntax
( ~for*/sum ...)
syntax
( ~for*/product ...)
syntax
( ~for*/hash ...)
syntax
( ~for*/hasheq ...)
syntax
( ~for*/hasheqv ...)
syntax
( ~for*/hashalw ...)
'((2 1) (4 3) (6 5))
'((2 1 6 5) (4 3 8 7))
'((2 1 6 5))
'((4 3 8 7))
'((4 1 8 7))
'(1)
'(1 2)
'(1)
'(1 2)
'((1 4) (1 5) (1 6) (2 4) (2 5) (2 6) (3 4) (3 5) (3 6))
'((1 4) (1 5) (1 6) (2 4) (2 5) (2 6) (3 4) (3 5) (3 6))
'((3 4) (2 3) (1 2))
21
21
#t
#f
#f
[ax][by])'((1 4)
(1 5)
(1 6)
(2 4)
(2 5)
(2 6)
(3 4)
(3 5)
(3 6)
(10 13)
(10 14)
(10 15)
(11 13)
(11 14)
(11 15)
(12 13)
(12 14)
(12 15))
'((1 4)
(1 5)
(1 6)
(2 4)
(2 5)
(2 6)
(3 4)
(3 5)
(3 6)
(10 13)
(10 14)
(10 15)
(11 13)
(11 14)
(11 15)
(12 13)
(12 14)
(12 15))
'((0 . 0)
(0 . 1)
(0 . 0)
(0 . 1)
(0 . 2)
(0 . 3)
(1 . 0)
(1 . 1)
(1 . 2)
(1 . 3)
(2 . 0)
(2 . 1)
(2 . 2)
(2 . 3))
'((0 . 0)
(0 . 1)
(0 . 0)
(0 . 1)
(0 . 2)
(0 . 3)
(1 . 0)
(1 . 1)
(1 . 2)
(1 . 3)
(2 . 0)
(2 . 1)
(2 . 2)
(2 . 3))
'((0 . 0)
(0 . 1)
(0 . 0)
(0 . 1)
(0 . 2)
(0 . 3)
(1 . 0)
(1 . 1)
(1 . 2)
(1 . 3)
(2 . 0)
(2 . 1)
(2 . 2)
(2 . 3))
[cx])'((1 2 3 4 0) (5 6 7 8 0) (5 6 7 8 1) (5 6 7 8 2) (5 6 7 8 3) (5 6 7 8 4))
'((1 2 3 4 0) (5 6 7 8 0) (5 6 7 8 1) (5 6 7 8 2) (5 6 7 8 3) (5 6 7 8 4))
Only defining match -specific new binding instances are currently possible.
syntax
( define-match-bind (namex...))
> (bf(B204060))120
> keys'(c b a)
> vals'(3 2 1)
syntax
( ~struct struct-id(field...)struct-option...)
field = field-id| [field-idfield-option...]struct-option = #:mutable| #:supersuper-expr| #:inspectorinspector-expr| #:auto-valueauto-expr| #:guardguard-expr| #:propertyprop-exprval-expr| #:transparent| #:prefab| #:sealed| #:authentic| #:namename-id| #:extra-namename-id| #:constructor-nameconstructor-id| #:extra-constructor-nameconstructor-id| #:reflection-namesymbol-expr| #:methodsgen:name-idmethod-defs| #:omit-define-syntaxes| #:omit-define-valuesfield-option = #:mutable| #:automethod-defs = (definition...)
> (C?c)#t
> (C-ac)9
> (C-bc)8
> (C-cc)7
> (C-dc)6
> (set-C-d!c20)> (C-dc)20
syntax
([fieldcontract-expr]...)struct-option...)field = field-id| [field-idfield-option...]struct-option = #:mutable| #:auto-valueauto-expr| #:propertyprop-exprval-expr| #:transparent| #:omit-define-syntaxesfield-option = #:mutable| #:auto
> (D?d)#t
> (D-ad)200
> (D-bd)"abcdefghij"
> (D-cd)'(k l m n o p)
> (set-D-c!d'(qrs))> (D-cd)'(q r s)
> (dfd)213
syntax
([fieldcontract-expr]...)struct-option...)field = field-id| [field-idfield-option...]struct-option = #:mutable| #:auto-valueauto-expr| #:propertyprop-exprval-expr| #:transparent| #:omit-define-syntaxesfield-option = #:mutable| #:auto
> (E?e)#t
> (E-ae)200
> (E-be)"abcdefghij"
> (E-ce)'(k l m n o p)
> (set-E-c!e'(qrs))> (E-ce)'(q r s)
> (efe)213