examples.scrbl (11474B)
1 #lang scribble/manual 2 3 @(require racket/require 4 scribble/example 5 "orig.rkt" 6 (for-label subtemplate 7 (only-in syntax/parse/experimental/template) 8 (subtract-in racket/base subtemplate))) 9 10 @title{Examples} 11 12 This section contains a few (somewhat artificial) examples on how to use 13 @racketmodname[subtemplate]. Most of the examples here would be more wisely 14 written as functions, and @racketmodname[syntax/parse] would otherwise be 15 sufficient with slightly more verbose code. The tools offered by 16 @racketmodname[subtemplate] are more useful for complex macros, where 17 boilerplate should be elided as much as possible to leave the true structure 18 of the macro visible. 19 20 @section{Automatically deriving identifiers using subscripts} 21 22 When an identifier @racket[yᵢ] is encountered in a template, it is 23 automatically derived from the corresponding @racket[xᵢ]. In the following 24 example, @racket[tempᵢ] is implicitly bound to 25 @racket[#'(a/temp b/temp c/temp)], without the need to call 26 @racket[generate-temporaries]. 27 28 @examples[ 29 (require subtemplate/override) 30 (syntax-parse #'(a b c) 31 [(vᵢ …) 32 #'([tempᵢ vᵢ] …)])] 33 34 It is common in macros to save an expression in a temporary variable to avoid 35 executing it twice. The following example builds on the previous one to do so, 36 without the need to call @racket[generate-temporaries]. Note that the 37 temporary identifiers generated this way are hygienic: there will be no name 38 clashes with identifiers from the user, nor with identifiers directly created 39 by your macro. 40 41 @examples[ 42 (require racket/require 43 (for-syntax (subtract-in racket/base subtemplate/override) 44 subtemplate/override)) 45 (define-syntax sum 46 (syntax-parser 47 [(_ vᵢ …) 48 #'(let ([tempᵢ vᵢ] …) 49 (unless (integer? tempᵢ) 50 (printf "Warning: ~a should be an integer, got ~a.\n" 51 'vᵢ 52 tempᵢ)) 53 … 54 (+ tempᵢ …))])) 55 (sum 1 2 3) 56 (sum 1 (begin (displayln "executed once") 2) 3) 57 (sum 1 (+ 3 0.14) 3)] 58 59 If you run out of unicode subscripts, characters following the last @racket[_] 60 are treated as the subscript: 61 62 @examples[ 63 (require subtemplate/override) 64 (syntax-parse #'(a b c) 65 [(v_foo …) 66 #'([temp_foo v_foo] …)])] 67 68 @section{Automatically extracting plain values from syntax objects} 69 70 In most cases, you do not have to call @racket[syntax->datum] anymore, as 71 @racketmodname[subtemplate] implicitly extracts the value of syntax pattern 72 variables. Do not rely too much on this feature, though, as future versions 73 may require explicit escapement with a concise shorthand, like 74 @racket[,pattern-variable] or @RACKET[#,pattern-variable]. 75 76 @examples[ 77 #:escape UNSYNTAX 78 (require racket/require 79 (for-syntax (subtract-in racket/base subtemplate/override) 80 subtemplate/override)) 81 (define-syntax nested 82 (syntax-parser 83 [(_ n v) 84 (if (> n 0) (code:comment "No need for syntax-e") 85 #`(list (nested #,(sub1 n) v)) (code:comment "No need for syntax-e") 86 #'v)])) 87 (nested 5 '(a b c))] 88 89 The implicit @racket[syntax->datum] also works on pattern variables which have 90 a non-zero ellipsis depth: 91 92 @examples[ 93 (require subtemplate/override) 94 (syntax-parse #'(1 2 3 4 5) 95 [(v …) 96 (define sum (apply + v)) 97 (if (> sum 10) 98 "foo" 99 "bar")])] 100 101 @section{Function application enhancements} 102 103 Why bother ourselves with @racket[apply]? Let's just write what we want: 104 105 @examples[ 106 (require subtemplate/override) 107 (syntax-parse #'(1 2 3 4 5) 108 [(v …) 109 (if (> (+ v …) 10) 110 "foo" 111 "bar")])] 112 113 Ellipses work as you expect when used in expressions: 114 115 @examples[ 116 (require subtemplate/override) 117 (define/syntax-parse ((vᵢⱼ …) …) #'((1 2 3 4) (5 6))) 118 (define/with-syntax (xₖ …) #'(a b c)) 119 (+ vᵢⱼ … …) 120 (define average (/ (+ vᵢⱼ … …) (length (list vᵢⱼ … …)))) 121 average 122 (max (min vᵢⱼ …) …) 123 (list vᵢⱼ … … xₖ …) 124 (list (list (+ vᵢⱼ 1) …) … (symbol->string xₖ) …) 125 (list (list vᵢⱼ …) … xₖ …) 126 (code:comment "Automatically derived symbols:") 127 (list (list yᵢⱼ …) …) 128 (list yₖ …) 129 (code:comment "Same ids as the yₖ ones above:") 130 #'(yₖ …) 131 ] 132 133 Here is another trick with ellipses: @racket[((vᵢ …) …)] should normally call 134 @racket[1] with arguments @racket[2 3 4], and @racket[5] with the argument 135 @racket[6], and then call the result of the first with the result of the 136 second as an argument. Since in most cases this is not what you want, the 137 @racket[list] function is implicitly called when the second element of an 138 application form is an ellipsis (do not abuse it, the semantics are a bit at 139 odds with the usual ones in Racket and might be surprising for people reading 140 your code): 141 142 @examples[ 143 (require subtemplate/override) 144 (define/syntax-parse ((vᵢⱼ …) …) #'((1 2 3 4) (5 6))) 145 ((vᵢⱼ …) …) 146 (vᵢⱼ … …) 147 (((+ vᵢⱼ 1000) …) …) 148 (code:comment "Automatically derived symbols:") 149 ((yᵢⱼ …) …) 150 (yᵢⱼ … …)] 151 152 Ellipses surprisingly also work on @racket[define], 153 @racket[define/with-syntax] and @racket[define/syntax-parse]: 154 155 @examples[ 156 (require subtemplate/override) 157 (define/syntax-parse ((v …) …) #'((1 2 3 4) (5 6))) 158 (define/syntax-parse (x …) #'("a" "b" "c")) 159 (begin 160 (define w (+ v 1)) … … 161 (define/syntax-parse y:id (string->symbol x)) …) 162 w 163 #'(y …)] 164 165 Since the trick is pulled off by a custom @racket[begin] form, provided by 166 @racketmodname[subtemplate], it will not work as expected at the REPL unless 167 you explicitly wrap the define and ellipses with a @racket[begin] form, as 168 done above. Within a module, however, this should work fine. 169 170 @section{Ellipsis-preserving @racket[unsyntax]} 171 172 Racket's @orig:syntax and @orig:template from 173 @racketmodname[syntax/parse/experimental/template] both forget the current 174 ellipsis position within an @racket[unsyntax] form. This makes it difficult to 175 perform simple changes to each element of a pattern variable under ellipses. 176 @racketmodname[syntax/parse/experimental/template] provides template 177 metafunctions, but they are unpractical for one-off small-scale alterations. 178 With @racket[subtemplate], @RACKET[#,e] and @RACKET[#,@e] both preserve the 179 current ellipsis position, meaning that uses of @racket[syntax], 180 @racket[quasisyntax], @racket[template] and so on within @racket[e] will use 181 the currently-focused portion of pattern variables under ellipses. 182 183 @examples[ 184 #:escape UNSYNTAX 185 (require subtemplate/override racket/list) 186 (define sd syntax->datum) 187 (define/syntax-parse ((v …) …) #'((1 2 3 4) (5 6))) 188 (sd #`(foo #,(+ v …) …)) 189 (code:comment "Quote, escape, re-quote, re-escape, re-quote:") 190 (sd #`(foo #,(cons (length (syntax->list #'(v …))) 191 #`(#,(add1 (syntax-e #'v)) …)) 192 …)) 193 (code:comment "Concise version of the above:") 194 (sd #`(foo (#,(length (v …)) #,(add1 v) …) …)) 195 (sd #`(foo #,(length (syntax->list #'(v …))) …)) 196 (sd #`(foo #,(length (list v …)) …)) 197 (sd #`(foo (#,(add1 v) …) …)) 198 (sd #`(foo #,(add1 v) … …)) 199 (sd #`(foo #,@(range v) … …))] 200 201 It is still possible to get the traditional full-escape behaviour with 202 @RACKET[#,,e] instead of @racket[unsyntax], and @RACKET[#,@,e] or 203 @RACKET[#,,@e] instead of @racket[unsyntax-splicing]: 204 205 @examples[ 206 #:escape UNSYNTAX 207 (require subtemplate/override racket/list syntax/stx) 208 (define sd syntax->datum) 209 (define/syntax-parse ((x v …) …) #'((10 1 2 3 4) (100 5 6))) 210 x 211 v 212 (sd #`(foo (x #,,#'(x …)) …)) 213 (sd #`(foo (x #,,(stx-map (λ (x) (add1 (syntax-e x))) #'(x …))) …)) 214 (sd #`(foo (x #,,(list (list (add1 v) …) …)) …)) 215 (sd #`(foo (x #,,(((add1 v) …) …)) …)) 216 (sd #`(foo (x #,,(stx-map (λ (x) (length (syntax->list x))) 217 #'((v …) …))) …)) 218 (sd #`(foo (x #,,((length (v …)) …)) …)) 219 (sd #`(foo ((v …) #,,((length (v …)) …)) …)) 220 (sd #`(foo (x #,,@((length (v …)) …)) …)) 221 (sd #`(foo (x #,@,(range (length (x …)))) …)) 222 (sd #`(foo (v … #,,@((range (length (v …))) …)) …))] 223 224 @section{Splicing and conditional template elements} 225 226 The splicing form @racket[?@] as well as @racket[??] should be familiar to 227 users of @racketmodname[syntax/parse/experimental/template]. The 228 @racketmodname[subtemplate] library provides overridden versions which also 229 work outside of syntax templates, as well as a few extras: 230 231 @examples[ 232 (require subtemplate/override) 233 (define/syntax-parse ({~optional {~or k:keyword b:boolean i:nat}} 234 {~and {~or (v …) s:str}} …) 235 #'(#:a-keyword (1 2 3 4) "foo" (5 6))) 236 (list (?? (+ v …) 237 (string-length s)) …) 238 (list (?? (?@ v …) 239 (string-length s)) …) 240 (list 'x (?@@ '(y y y) (?? (?@ (list 'c v …))) …) 'z) 241 (list (?if s "string" "list of numbers") …) 242 (?cond [k (list (?? (?@ 'there-was-a-keyword v …)) …)] 243 [b (list (?? (?@ 'there-was-a-boolean (?? v s) …)) …)] 244 [else (list (?? (?@ (?? i) v …)) …)]) 245 (list (?attr k) (?attr b) (?attr i)) 246 (?? k b i 'none)] 247 248 The @racket[?@@] splicing form performs two levels of unwrapping (it can be 249 understood as a way to perform @racket[(?@ (append elements …))]). The 250 @racket[(?if _condition _true _false)] is a generalisation of @racket[??], 251 which accepts a @racket[_condition] template, and produces the 252 @racket[_true]-template if there are no missing elements in the 253 @racket[_condition] (in the sense of @racket[~optional]), and produces 254 @racket[_false] otherwise. @racket[?cond] is a shorthand for a sequence of 255 nested @racket[?if] forms, and @racket[(?attr a)] returns a boolean indicating 256 the presence of the attribute (it is a shorthand for @racket[(?if a #t #f)]). 257 Finally, @racket[??] itself is not limited to two alternatives. When given a 258 single alternative, @racket[??] implicitly uses @racket[(?@)], i.e. the empty 259 splice, as the second alternative (this is the behaviour of the version from 260 @racketmodname[syntax/parse/experimental/template]). When two or more 261 alternatives are specified, each one is tried in turn, and the last one is 262 used as a fallback (i.e. an empty splice is @emph{not} implicitly added as a 263 last alternative when there are already two or more alternatives). 264 265 The @racket[?if] form is useful when one would want to write a @racket[??] 266 form, where the triggering condition should not appear in the left-hand-side 267 of @racket[??], for example when changing the generated code based on the 268 presence of a keyword passed to the macro: 269 270 @examples[ 271 (require racket/require 272 (for-syntax (subtract-in racket/base subtemplate/override) 273 subtemplate/override)) 274 (define-syntax my-sort 275 (syntax-parser 276 [(_ {~optional {~and reverse-kw #:reverse}} v …) 277 #'(sort (list v …) (?if reverse-kw > <))])) 278 (my-sort 3 2 1) 279 (my-sort #:reverse 3 2 1)] 280 281 Note that @racket[?@] and @racket[?@@] work on regular lists (but ellipses do 282 not), and they can splice multiple arguments into the surrounding function 283 call. One last application trick is the dotted tail argument, used as a 284 shorthand for @racket[apply]: 285 286 @examples[ 287 (require subtemplate/override racket/function) 288 (define l '((1 2 3) (4 5 6))) 289 (vector 'a (?@ l) 'c) 290 (+ 0 (?@@ (?@@ l)) 7) 291 (vector 'a (?@@ (?@@ l)) 'c) 292 (+ 0 (?@@ . l) 7) 293 (vector 'a (?@@ . l) 'c) 294 (map + . l)]