Racket Generic Binding Forms
1 Generic Binding Instances
$
~vs
$:
$list
$null
$stx
$and
$c
2 Core Generic Binding Forms
~define
~def
~d
~define/  contract
~lambda
~lam
~l
~case-lambda
~case-lam
~case-define
~case-def
~let
~let*
~letrec
3 Generic Comprehension Forms
~for
~for/  list
~for/  lists
~for/  vector
~for/  fold
~for/  foldr
~for/  first
~for/  last
~for/  or
~for/  and
~for/  sum
~for/  product
~for/  hash
~for/  hasheq
~for/  hasheqv
~for/  hashalw
~for*
~for*/  list
~for*/  lists
~for*/  vector
~for*/  fold
~for*/  foldr
~for*/  first
~for*/  last
~for*/  or
~for*/  and
~for*/  sum
~for*/  product
~for*/  hash
~for*/  hasheq
~for*/  hasheqv
~for*/  hashalw
4 Implementing New Generic Binding Instances
define-match-bind
~struct
~struct/  contract
~define-struct/  contract
8.12

Racket Generic Binding Forms🔗ℹ

Stephen Chang <stchang at racket-lang dot org>
and Alexander Knauth <alexander at knauth dot org>

 (require generic-bind) package: generic-bind

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.

1 Generic Binding Instances🔗ℹ

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.

Generic binding instances are further separated into two categories:
  • 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)

The match binding instance. The required pattern is a match pattern. May be used in any context.

Other generic binding instances can be nested within the match pattern.

syntax

(~vs b ...)

 
b = define-allowable-generic-binding
Binding instance for values. May only be used in "let" contexts (which means not in ~define or ~lambda for example).

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 ...)

Same as ~vs.

syntax

($: x xs)

A match binding instance where the outer match pattern is cons. Equivalent to ($ (cons x xs)).

syntax

($list x ...)

($list x ... : rst)
A match binding instance where the outer match pattern is either list or list-rest, depending whether a rest argument is supplied. Equivalent to either ($ (list x ...)) or ($ (list-rest x ... rst)).

value

$null : _

A match binding instance for null.

syntax

($stx pattern pattern-directive ...)

A binding instance for parsing syntax-objects with syntax-parse.

syntax

($and b ...)

 
b = generic-binding
A binding instance that binds each b binding.

syntax

($c db contract-expr)

($c b (values contract-expr ...))
 
db = define-allowable-generic-binding
     
b = generic-binding
A binding instance that binds b or db with a contract.

2 Core Generic Binding Forms🔗ℹ

syntax

(~define b body)

(~define (f db ...) body ...)
 
b = generic-binding
  | identifier?
     
db = define-allowable-generic-binding
  | identifier?
Same as define but each binding site (except for the function name) may be either an identifier or a generic binding instance.

When using ~define to define a function, any generic binding must be define-allowable. (So the ~vs values-binding form is not allowed.)

define-like, non-function examples:
> (~define x1 (+ 1 2))
> x1

3

> (~define x2 (list 1 2))
> x2

'(1 2)

Non-function examples with generic bind forms:
> (~define ($ (list y1 y2)) (list 10 20))
> y1

10

> y2

20

> (~define ($ (list (cons y3 y4) y5)) (list (cons 20 30) 40))
> y3

20

> y4

30

> y5

40

> (~define ( v1 v2) (values 101 202))
> v1

101

> v2

202

> (~define ( ($ (list x4 x5)) x6) (values (list 99 999) 9999))
> x4

99

> x5

999

> x6

9999

> (struct A (x y))
> (~define ($ (A x7 y7)) (A 101 202))
> x7

101

> y7

202

> (~define ($stx ((~seq kw:keyword arg:expr) ...)) #'(#:a 1 #:b 2 #:c 3))
> #'(kw ...)

#<syntax:eval:25:0 (#:a #:b #:c)>

> #'(arg ...)

#<syntax:eval:26:0 (1 2 3)>

> #'([kw . arg] ...)

#<syntax:eval:27:0 ((#:a . 1) (#:b . 2) (#:c . 3))>

define-like function examples:
> (~define (f1 x [y 10] #:z [z 0]) (+ x y z))
> (f1 100)

110

> (f1 100 200)

300

> (f1 100 200 #:z 300)

600

> (~define (f3 . rst) rst)
> (f3 1 2 3)

'(1 2 3)

> (f3)

'()

> (~define (f4 x y . rst) (cons x (cons y rst)))
> (f4 1 2 3 4 5 6)

'(1 2 3 4 5 6)

> (f4 1 2)

'(1 2)

Function examples using generic bind forms:
> (~define (f2 ($ (list x y))) (- x y))
> (f2 (list 145 45))

100

> (~define (g1 ($ (list (list a b) y ...))) (apply + a b y))
> (g1 (list (list 101 202) 303))

606

> (~define (f5 ($ (list (list x y) z)) . rst) (cons x (cons y (cons z rst))))
> (f5 (list (list 1 2) 3))

'(1 2 3)

> (f5 (list (list 1 2) 3) 4 5)

'(1 2 3 4 5)

> (~define (gg ($ xxx)) (add1 xxx))
> (gg 10001)

10002

> (~define (ggg ($ _)) 12345)
> (ggg 5432)

12345

> (~define (gggg ($ 11111)) 22222)
> (gggg 111)

match-define: no matching clause for 111

> (gggg 11111)

22222

> (~define (f20 ($list x y z : xs)) (+ x y z (length xs)))
> (f20 (list 10 20 30 40 50 60 70 80 90))

66

> (~define (f21 ($: x xs)) (+ x (length xs)))
> (f21 (list 10 20 30 40 50 60 70 80 90))

18

Argument-with-default and keyword binding positions support generic bindings too:
> (~define (fkw1 [($list x y) (list 1 2)]) (+ x y 10))
> (fkw1)

13

> (fkw1 (list 10 20))

40

> (fkw1 10)

match-define: no matching clause for 10

> (~define (fkw2 #:A ($list x y)) (+ x y 10))
> (fkw2 #:A (list 1 2))

13

> (~define (fkw3 #:B [($list x y) (list 1 2)]) (+ x y 10))
> (fkw3 #:B (list 10 20))

40

> (fkw3 #:B 10)

match-define: no matching clause for 10

syntax

(~def ...)

Same as ~define.

syntax

(~d ...)

Same as ~define.

syntax

(~define/contract b contract-expr body)

(~define/contract (f db ...) contract-expr body ...)
 
b = generic-binding
  | identifier?
     
db = define-allowable-generic-binding
  | identifier?
like define/contract, except allowing generic binding instances like ~define.

syntax

(~lambda db body ...)

(~lambda (db ...) body ...)
 
db = define-allowable-generic-binding
  | identifier?
Same as lambda but each binding site may be either an identifier or a (define-allowable) generic binding instance. (So the ~vs values-binding form is not allowed.)

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 ...)

Same as ~lambda.

syntax

(~l ...)

Same as ~lambda.

syntax

( ...)

Same as ~lambda.

Examples of standard, lambda-like behavior:
> (( (x) x) 111)

111

> (( rst rst) 1 2 3)

'(1 2 3)

> (( (x [y 0] #:z z #:a [a 10]) (+ x y z a)) 1 #:z 10)

21

> (( (x [y 0] #:z z #:a [a 10]) (+ x y z a)) 1 22 #:z 10)

43

> (( (x [y 0] #:z z #:a [a 10]) (+ x y z a)) 1 #:z 10 #:a 111)

122

> ((~lambda (x [y 0] #:z z #:a [a 10]) (+ x y z a)) 1 #:z 10 #:a 111)

122

Examples with generic bind forms:
> ((~lambda ($: x xs) (append xs (list x))) (list 1 2 3 4 5))

'(2 3 4 5 1)

> ((~lambda (f ($: x xs)) (cons (f x) xs)) add1 (list 1 2 3 4))

'(2 2 3 4)

> ((~lambda (f ($list)) (f 1)) add1 null)

2

> ((~lambda (f ($list)) (f 1)) add1 (list 1 2 3))

match-define: no matching clause for '(1 2 3)

> (( (($ (list x y)) ($ (cons a b))) (+ a b x y))
                 (list 1 2) (cons 3 4))

10

> (( (x y ($ (A a b))) (+ x y a b)) 10 20 (A 30 40))

100

Example of single-arg generic bind support:
> (( ($ (list x y)) (+ x y)) (list 14 56))

70

The next example may look like a single-arg generic bind, but since ~vs is not allowed in this context, it is treated as an identifier and shadows the existing binding for ~vs.
> (( (~vs v1 v2) (+ ~vs v1 v2)) 1 2 3)

6

Here is a disallowed generic bind used in the standard way, resulting in an error:
> ( ((~vs v1 v2)) (+ v1 v2))

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

Generic bind forms are allowed in keyword and arg-with-default binding positions too:
> (( ([($: x xs) (list 1 2)]) (+ x (length xs) 20)))

22

> (( ([($: x xs) (list 1 2)]) (+ x (length xs) 20)) (list 1 2 3 4))

24

> (( (#:C ($: x xs)) (append xs (list x))) #:C (list 1 2 3))

'(2 3 1)

> (( (#:D [($: x xs) (list 10 20 30)]) (append xs (list x))))

'(20 30 10)

> (( (#:D [($: x xs) (list 10 20 30)]) (append xs (list x))) #:D (list 1 2 3))

'(2 3 1)

syntax

(~case-lambda clause ...)

 
clause = (header body ...)
A "simulation" of a case-lambda that also acccepts generic binds.

Since case-lambda only distinguishes between cases based on the number of arguments, ~case-lambda cannot be defined in terms of case-lambda. Instead ~case-lambda defines a series of lambdas, and then tries to apply each one, backtracking on exn:misc:match?.

Examples:
> (define casemap1
    (~case-lambda [(f $null) null]
                  [(f ($: x xs)) (cons (f x) (casemap1 f xs))]))
> (casemap1 add1 null)

'()

> (casemap1 add1 (list 1))

'(2)

> (casemap1 add1 (list 1 2 3 4))

'(2 3 4 5)

> (casemap1 add1 1)

match-define: no matching clause for 1

syntax

(~case-lam clause ...)

Same as ~case-lambda

syntax

(~case-define f clause1 ...)

(~case-define f clause2 ...)
 
clause1 = (header body ...)
     
clause2 = (b ...  body ...)
Syntax for naming a ~case-lambda

Examples:
> (~case-define new-map1
    [(f $null) null]
    [(f ($: x xs)) (cons (f x) (new-map1 f xs))])
> (new-map1 add1 null)

'()

> (new-map1 add1 (list 1))

'(2)

> (new-map1 add1 (list 1 2))

'(2 3)

> (~case-define new-filter1
    [(p? $null) null]
    [(p? ($: x xs)) (if (p? x) (cons x (new-filter1 p? xs)) (new-filter1 p? xs))])
> (new-filter1 even? null)

'()

> (new-filter1 even? (list 1))

'()

> (new-filter1 even? (list 1 2 3 4 5))

'(2 4)

> (~case-define new-foldl1
    [(f base $null) base]
    [(f base ($: x xs)) (new-foldl1 f (f x base) xs)])
> (new-foldl1 - 0 null)

0

> (new-foldl1 - 0 (list 1))

1

> (foldl - 0 (list 1))

1

> (new-foldl1 - 0 (list 1 2))

1

> (foldl - 0 (list 1 2))

1

> (~case-define new-foldr1
    [(f base $null) base]
    [(f base ($: x xs)) (f x (new-foldr1 f base xs))])
> (new-foldr1 - 0 null)

0

> (new-foldr1 - 0 (list 1))

1

> (foldr - 0 (list 1))

1

> (new-foldr1 - 0 (list 1 2))

-1

> (foldr - 0 (list 1 2))

-1

syntax

(~case-def clause ...)

Same as ~case-define

Examples:
> (~case-def new-map [f $null  null]
                     [f ($: x xs)  (cons (f x) (new-map f xs))])
> (new-map add1 null)

'()

> (new-map add1 (list 1))

'(2)

> (new-map add1 (list 1 2))

'(2 3)

> (~case-def new-filter [p? $null  null]
                        [p? ($: (? p? x) xs)  (cons x (new-filter p? xs))]
                        [p? ($: x xs)  (new-filter p? xs)])
> (new-filter even? null)

'()

> (new-filter even? (list 1))

'()

> (new-filter even? (list 1 2 3 4 5))

'(2 4)

> (~case-def new-foldl [f base $null  base]
                       [f base ($: x xs)  (new-foldl f (f x base) xs)])
> (new-foldl - 0 null)

0

> (new-foldl - 0 (list 1))

1

> (foldl - 0 (list 1))

1

> (new-foldl - 0 (list 1 2))

1

> (foldl - 0 (list 1 2))

1

> (~case-def new-foldr [f base $null  base]
                       [f base ($: x xs)  (f x (new-foldr f base xs))])
> (new-foldr - 0 null)

0

> (new-foldr - 0 (list 1))

1

> (foldr - 0 (list 1))

1

> (new-foldr - 0 (list 1 2))

-1

> (foldr - 0 (list 1 2))

-1

syntax

(~let loop ([db e] ...) body ...)

(~let ([b e] ...) body ...)
 
db = define-allowable-generic-bind
  | identifier?
     
b = generic-bind
  | identifier?
Same as let, but with generic bind support. If a name is given to the let, then the bindings must be define-allowable, since it’s essentially defining a function. If no name is given to the ~let, then any generic bind is allowed.

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.

Examples:
> (define x55 155)
> (~let ([x55 (add1 x55)]) x55)

156

> (define x56 156)
> (~let ([x56 157] [x57 x56]) x57)

156

> (~let ([($ (list x58 x59)) (list 158 159)]) (list x59 x58))

'(159 158)

> (~let ([(~vs v17 v27) (values 17 27)]) (+ v17 v27))

44

> (~let ([(~vs ($ (list x18 y18)) v18) (values (list 18 19) 20)])
                      (+ x18 y18 v18))

57

> (~let ([x 1] [x 2]) x)

eval:137:0: define-values: duplicate binding name

  at: x

  in: (define-values (x) (values g922))

> (~let ([($ (list x y)) (list 1 2)] [x 3]) x)

eval:138:0: define-values: duplicate binding name

  at: x

  in: (define-values (x) (values g924))

> (~let ([x 3] [($ (list x y)) (list 1 2)]) x)

eval:139:0: define-values: duplicate binding name

  at: x

  in: (define-values (x y) (let-local-keys ((g43109

stx-param929)) (let-values (((temp930) (values g928)))

(match*/derived (temp930) (match-define (list x y) (values

g928)) (((list x y)) (values x y))))))

> (~let ([($ (list x y)) (list 1 2)] [($ (list x y)) (list 3 4)]) (list x y))

eval:140:0: define-values: duplicate binding name

  at: x

  in: (define-values (x y) (let-local-keys ((g43109

stx-param935)) (let-values (((temp936) (values g932)))

(match*/derived (temp936) (match-define (list x y) (values

g932)) (((list x y)) (values x y))))))

> (~let ([($ (list x y)) (list 1 2)] [(~vs x y) (list 3 4)]) (list x y))

eval:141:0: define-values: duplicate binding name

  at: x

  in: (define-values (x) g942)

> (~let ([($ (list x x)) (list 2 2)]) x)

2

> (let ([x 12345]) (~let ([x 40] [y x]) y))

12345

> (let ([x 12345]) (~let ([x 40] [y 1] [z x]) z))

12345

> (let ([x 12345] [y 5432]) (~let ([x 40] [y 23] [z y]) z))

5432

> (~let ([x59 x59]) x59)

x59: undefined;

 cannot reference an identifier before its definition

  in module: top-level

> (~let ([f (λ (x) (if (zero? x) 1 (* x (f (sub1 x)))))]) (f 10))

f: undefined;

 cannot reference an identifier before its definition

  in module: top-level

> (~let L ([($ (list x y ...)) (list 1 2 3 4 5)] [n 4])
        (if (zero? n) 0
            (+ n x (L y (sub1 n)))))

20

> (let loop ([x 1] [x 2]) x)

eval:149:0: let: duplicate identifier

  at: x

  in: (let loop ((x 1) (x 2)) x)

> (~let loop ([x 1] [x 2]) x)

eval:150:0: lambda: duplicate argument name

  at: x

  in: (lambda (x x) x)

> (define x8 109)
> (let loop ([x8 1] [y x8]) y)

109

> (~let loop ([x8 1] [y x8]) y)

109

syntax

(~let* ([b e] ...) body ...)

 
b = generic-bind
  | identifier?
Same as let*, but with generic bind support.

Examples:
> (~let* ([x 46436] [y x]) y)

46436

> (~let* ([($ (list x y)) (list 1010 2020)] [z (+ x y)]) z)

3030

> (~let* ([( v1 v2) (values 4040 5050)] [z (+ v1 v2)]) z)

9090

> (~let* ([( v3 ($ (list xy yx))) (values 202 (list 303 404))]
                        [z (+ v3 (- yx xy))])
                       z)

303

> (~let* ([x 1122]
                        [( ($ (cons ab bc)) ($ (list-rest y ys)))
                         (values (cons x (* x 2)) (list x (add1 x) (sub1 x)))])
                       (+ (- bc ab) (- y (+ (car ys) (cadr ys)))))

0

> (~let* ([x 101] [x 202]) x)

202

syntax

(~letrec ([b e] ...) body ...)

 
b = generic-bind
  | identifier?
Same as letrec, but with generic bind support.

Examples:
> (require math/number-theory)
> (~letrec ([x x]) x)

x: undefined;

 cannot use before initialization

> (~letrec ([f (λ (x) (if (zero? x) 1 (* x (f (sub1 x)))))]) (f 10))

3628800

> (factorial 10)

3628800

> (~letrec ([evn? (λ (x) (if (zero? x) #t (od? (sub1 x))))]
             [od? (λ (x) (if (zero? x) #f (evn? (sub1 x))))])
     (evn? 10))

#t

> (~letrec ([( evn? od?)
              (values (λ (x) (if (zero? x) #t (od? (sub1 x))))
                      (λ (x) (if (zero? x) #f (evn? (sub1 x)))))])
     (evn? 10))

#t

> (~letrec ([($ (list evn? od?))
              (list (λ (x) (if (zero? x) #t (od? (sub1 x))))
                    (λ (x) (if (zero? x) #f (evn? (sub1 x)))))])
            (and (od? 101) (evn? 10)))

#t

> (~letrec ([( evn? ($ (list od?)))
              (values (λ (x) (if (zero? x) #t (od? (sub1 x))))
                      (list (λ (x) (if (zero? x) #f (evn? (sub1 x))))))])
            (and (od? 101) (evn? 10)))

#t

3 Generic Comprehension Forms🔗ℹ

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 ...)

Allows generic binds in sequence clauses, not accumulator clauses.

syntax

(~for/foldr ...)

Allows generic binds in sequence clauses, not accumulator clauses.

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 ...)

Allows generic binds in sequence clauses, not accumulator clauses.

syntax

(~for*/foldr ...)

Allows generic binds in sequence clauses, not accumulator clauses.

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 ...)

Examples:
> (~for/list ([($ (list x y)) '((1 2) (3 4) (5 6))]) (list y x))

'((2 1) (4 3) (6 5))

> (~for/list
   ([($ (list x y)) '((1 2) (3 4))]
    [($ (list a b)) '((5 6) (7 8))])
   (list y x b a))

'((2 1 6 5) (4 3 8 7))

> (~for/list
   ([($ (list x y)) '((1 2) (3 4))]
    [($ (list a b)) '((5 6) (7 8))]
    #:when (= x 1))
   (list y x b a))

'((2 1 6 5))

> (~for/list
   ([($ (list x y)) '((1 2) (3 4))]
    [($ (list a b)) '((5 6) (7 8))]
    #:unless (= x 1))
   (list y x b a))

'((4 3 8 7))

> (~for/list
   ([($ (list x y)) '((2 2) (1 4) (1 4))]
    [($ (list a b)) '((5 6) (6 7) (7 8))]
    #:when (= x 1)
    #:unless (= a 6))
   (list y x b a))

'((4 1 8 7))

> (~for/list ([x '(1 2 3)] #:break (= x 2)) x)

'(1)

> (~for/list ([x '(1 2 3)] #:final (= x 2)) x)

'(1 2)

> (~for*/list ([x '(1 2 3)]) #:break (= x 2) x)

'(1)

> (~for*/list ([x '(1 2 3)]) #:final (= x 2) x)

'(1 2)

> (~for/list ([x '(1 2 3)] #:when #t [y '(4 5 6)] #:when #t) (list x y))

'((1 4) (1 5) (1 6) (2 4) (2 5) (2 6) (3 4) (3 5) (3 6))

> (~for*/list ([x '(1 2 3)] [y '(4 5 6)]) (list x y))

'((1 4) (1 5) (1 6) (2 4) (2 5) (2 6) (3 4) (3 5) (3 6))

> (require racket/generator)
> (~for/list ([($ (list x y)) (in-generator (let loop ([n 3])
                                              (unless (zero? n)
                                                (yield (list n (add1 n)))
                                                (loop (sub1 n)))))])
             (list x y))

'((3 4) (2 3) (1 2))

> (~for/fold ([sum 0]) ([x '(1 2 3 4 5 6)]) (+ x sum))

21

> (for/fold ([sum 0]) ([x '(1 2 3 4 5 6)]) (+ x sum))

21

> (~for/and ([x (list #t #f #t)]) (displayln x) x)

#t

#f

#f

> (~for*/list ([($ (list x y)) (list (list (list 1 2 3) (list 4 5 6))
                                    (list (list 10 11 12) (list 13 14 15)))]
               [a x] [b y])
             (list a b))

'((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))

> (for*/list ([lst (list (list (list 1 2 3) (list 4 5 6))
                         (list (list 10 11 12) (list 13 14 15)))]
              [a (car lst)] [b (cadr lst)])
    (list a b))

'((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))

> (~for*/list ([(~vs v1 v2) (in-hash (hash 1 2 3 4))]
               [x v1] [y v2])
              (cons x y))

'((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))

> (for*/list ([(v1 v2) (in-hash (hash 1 2 3 4))]
             [x v1] [y v2])
            (cons x y))

'((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))

> (~for*/list ([(v1 v2) (in-hash (hash 1 2 3 4))]
              [x v1] [y v2])
             (cons x y))

'((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))

> (~for*/list ([(~vs ($ (list x y)) ($ (list a b)))
                (in-hash (hash (list 1 2) (list 3 4) (list 5 6) (list 7 8)))]
               [c x])
              (list x y a b c))

'((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))

> (for*/list ([(lst1 lst2) (in-hash (hash (list 1 2) (list 3 4) (list 5 6) (list 7 8)))]
              [c (car lst1)])
    (list (car lst1) (cadr lst1) (car lst2) (cadr lst2) c))

'((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))

4 Implementing New Generic Binding Instances🔗ℹ

Only defining match-specific new binding instances are currently possible.

syntax

(define-match-bind (name x ...))

(define-match-bind name)
Defines a new binding instance $name that binds using the match pattern (name x ...).

> (struct B (x y z))
> (define-match-bind (B x y z))
> (~define (bf ($B x y z)) (+ x y z))
> (bf (B 20 40 60))

120

> (define-match-bind hash-table)
> (~define ($hash-table [keys vals] ...) (hash 'a 1 'b 2 'c 3))
> keys

'(c b a)

> vals

'(3 2 1)

syntax

(~struct struct-id (field ...) struct-option ...)

(~struct struct-id super-struct-id (field ...) struct-option ...)
 
field = field-id
  | [field-id field-option ...]
     
struct-option = #:mutable
  | #:super super-expr
  | #:inspector inspector-expr
  | #:auto-value auto-expr
  | #:guard guard-expr
  | #:property prop-expr val-expr
  | #:transparent
  | #:prefab
  | #:sealed
  | #:authentic
  | #:name name-id
  | #:extra-name name-id
  | #:constructor-name constructor-id
  | #:extra-constructor-name constructor-id
  | #:reflection-name symbol-expr
  | #:methods gen:name-id method-defs
  | #:omit-define-syntaxes
  | #:omit-define-values
     
field-option = #:mutable
  | #:auto
     
method-defs = (definition ...)
Exactly like struct except a new generic binding instance is also defined. Equivalent to using struct and define-match-bind.

> (~struct C (a b c [d #:mutable]))
Behaves like a struct-defined struct:
> (define c (C 9 8 7 6))
> (C? c)

#t

> (C-a c)

9

> (C-b c)

8

> (C-c c)

7

> (C-d c)

6

> (set-C-d! c 20)
> (C-d c)

20

Generic binding instance:
> (~define (cf ($C e f g h)) (+ e f g h))
> (cf c)

44

syntax

(~struct/contract struct-id
                  ([field contract-expr] ...)
                  struct-option ...)
(~struct/contract struct-id super-struct-id
                  ([field contract-expr] ...)
                  struct-option ...)
 
field = field-id
  | [field-id field-option ...]
     
struct-option = #:mutable
  | #:auto-value auto-expr
  | #:property prop-expr val-expr
  | #:transparent
  | #:omit-define-syntaxes
     
field-option = #:mutable
  | #:auto
Exactly like struct/contract except a new generic binding instance is also defined. Equivalent to using struct/contract and define-match-bind.

> (~struct/contract D ([a number?] [b string?] [[c #:mutable] list?]))
Behaves like a struct/contract-defined struct:
> (define d (D 200 "abcdefghij" '(k l m n o p)))
> (D? d)

#t

> (D-a d)

200

> (D-b d)

"abcdefghij"

> (D-c d)

'(k l m n o p)

> (set-D-c! d '(q r s))
> (D-c d)

'(q r s)

Generic binding instance:
> (~define (df ($D n s l)) (+ n (string-length s) (length l)))
> (df d)

213

syntax

(~define-struct/contract struct-id
                         ([field contract-expr] ...)
                         struct-option ...)
(~define-struct/contract (struct-id super-struct-id)
                         ([field contract-expr] ...)
                         struct-option ...)
 
field = field-id
  | [field-id field-option ...]
     
struct-option = #:mutable
  | #:auto-value auto-expr
  | #:property prop-expr val-expr
  | #:transparent
  | #:omit-define-syntaxes
     
field-option = #:mutable
  | #:auto
Exactly like define-struct/contract except a new generic binding instance is also defined. Equivalent to using define-struct/contract and define-match-bind.

> (~define-struct/contract E ([a number?] [b string?] [[c #:mutable] list?]))
Behaves like a define-struct/contract-defined struct:
> (define e (make-E 200 "abcdefghij" '(k l m n o p)))
> (E? e)

#t

> (E-a e)

200

> (E-b e)

"abcdefghij"

> (E-c e)

'(k l m n o p)

> (set-E-c! e '(q r s))
> (E-c e)

'(q r s)

Generic binding instance:
> (~define (ef ($E n s l)) (+ n (string-length s) (length l)))
> (ef e)

213