├── .gitignore ├── gh.css ├── COPYRIGHT ├── .github └── FUNDING.yml ├── fear-of-macros.jpg ├── macro-stepper.png ├── README.md ├── Makefile ├── add-to-head.rkt └── index.rkt /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | html/ 3 | fear-of-macros/ 4 | -------------------------------------------------------------------------------- /gh.css: -------------------------------------------------------------------------------- 1 | .strike { 2 | text-decoration: line-through; 3 | } 4 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 by Greg Hendershott. All rights reserved. 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: greghendershott 2 | custom: https://www.paypal.me/greghendershott 3 | -------------------------------------------------------------------------------- /fear-of-macros.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greghendershott/fear-of-macros/HEAD/fear-of-macros.jpg -------------------------------------------------------------------------------- /macro-stepper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greghendershott/fear-of-macros/HEAD/macro-stepper.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Fear of Macros](http://www.greghendershott.com/fear-of-macros/fear-of-macros.jpg "") 2 | 3 | ## What it is 4 | 5 | This is a rough draft of a practical guide to Racket macros. 6 | 7 | I started to write it not because I understand macros very well, but 8 | because I don't. 9 | 10 | ## Where to read it 11 | 12 | - [Multiple HTML files](https://www.greghendershott.com/fear-of-macros/index.html) 13 | - [One big HTML file](https://www.greghendershott.com/fear-of-macros/all.html) 14 | 15 | ## Feedback 16 | 17 | Feedback is welcome; please use Issues page here on GitHub. 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | scrbl := index.rkt 2 | 3 | www := fear-of-macros 4 | 5 | .PHONY: all clean html html-single html-multi 6 | 7 | all: html 8 | 9 | clean: 10 | rm -rf $(www) 11 | 12 | html: html-single html-multi 13 | racket add-to-head.rkt 14 | 15 | html-single: $(scrbl) 16 | raco scribble \ 17 | --html \ 18 | --dest $(www) \ 19 | --dest-name all.html \ 20 | ++style gh.css \ 21 | ++main-xref-in \ 22 | --redirect-main https://docs.racket-lang.org/ \ 23 | \ 24 | $(scrbl) 25 | 26 | html-multi: $(scrbl) 27 | raco scribble \ 28 | --htmls \ 29 | --dest-name $(www) \ 30 | ++style gh.css \ 31 | ++main-xref-in \ 32 | --redirect-main https://docs.racket-lang.org/ \ 33 | \ 34 | $(scrbl) 35 | 36 | ###################################################################### 37 | # S3 bucket deploy 38 | 39 | aws := aws --profile greg 40 | dest := s3://www.greghendershott.com/fear-of-macros/ 41 | cfid := E2LPR1YW069SHG 42 | 43 | .PHONY: deploy 44 | 45 | deploy: 46 | $(aws) s3 sync --no-follow-symlinks $(www) $(dest) 47 | $(aws) cloudfront create-invalidation --distribution-id $(cfid) --paths "/fear-of-macros/*" 48 | -------------------------------------------------------------------------------- /add-to-head.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; Realm of kludge: 4 | ;; 5 | ;; AFIK no way via Scribble to put something into the section. 6 | ;; 7 | ;; This reads all HTML files and injects some stuff immediately before the 8 | ;; closing tag. 9 | 10 | (define (meta k v) 11 | (format "" k v)) 12 | 13 | (define metas 14 | (string-append 15 | (meta "keywords" "Racket, macros, Scheme") 16 | (meta "description" "Practical Racket macros") 17 | (meta "author" "Greg Hendershott") 18 | (meta "charset" "utf-8"))) 19 | 20 | (define "") 21 | 22 | (define all (string-append metas )) 23 | (define subst (regexp-replace* "\n" all "")) ;minify 24 | 25 | (define (do-file path) 26 | (define old (file->string path)) 27 | (define new (regexp-replace old subst)) 28 | (with-output-to-file path 29 | (lambda () (display new)) 30 | #:mode 'text 31 | #:exists 'replace)) 32 | 33 | (require racket/runtime-path) 34 | (define-runtime-path here ".") 35 | (for ([path (find-files (lambda (path) 36 | (regexp-match? #rx"\\.html" path)) 37 | here)]) 38 | (do-file path)) 39 | -------------------------------------------------------------------------------- /index.rkt: -------------------------------------------------------------------------------- 1 | #lang scribble/manual 2 | 3 | @(require racket/sandbox 4 | scribble/eval 5 | scribble/racket 6 | racket/date 7 | (for-syntax racket/base) 8 | (for-label racket) 9 | (for-label racket/stxparam) 10 | (for-label syntax/parse) 11 | (for-label racket/splicing) 12 | (for-label racket/syntax)) 13 | @(define evaluator 14 | (parameterize ([sandbox-output 'string] 15 | [sandbox-error-output 'string] 16 | [sandbox-memory-limit #f]) 17 | (make-evaluator 'racket))) 18 | 19 | @(define typed/evaluator 20 | (parameterize ([sandbox-output 'string] 21 | [sandbox-error-output 'string] 22 | [sandbox-memory-limit #f]) 23 | (make-evaluator 'typed/racket))) 24 | 25 | @(define-syntax-rule (i body ...) 26 | (interaction #:eval evaluator body ...)) 27 | 28 | @(define (current-year) 29 | (number->string (date-year (current-date)))) 30 | 31 | @title[#:version ""]{Fear of Macros} 32 | @author[@hyperlink["http://www.greghendershott.com" 33 | "Greg Hendershott"]] 34 | @image["fear-of-macros.jpg"] 35 | @para{A practical guide to @hyperlink["https://www.racket-lang.org"]{Racket} macros.} 36 | @para[@smaller{Copyright (c) 2012-@current-year[] by Greg Hendershott. All rights reserved.}] 37 | @para[@smaller["Last updated " 38 | (parameterize ([date-display-format 'iso-8601]) 39 | (date->string (current-date) #t))]] 40 | @para{@hyperlink["https://github.com/greghendershott/fear-of-macros/issues" "Feedback and corrections"].} 41 | @para{@hyperlink["https://github.com/users/greghendershott/sponsorship" "Sponsor my work"] or @hyperlink["https://www.paypal.me/greghendershott" "donate"].} 42 | 43 | @table-of-contents{} 44 | 45 | @; ---------------------------------------------------------------------------- 46 | 47 | @section{Preface} 48 | 49 | I learned @hyperlink["https://www.racket-lang.org"]{Racket} after 25 50 | years of mostly using C and C++. 51 | 52 | Some psychic whiplash resulted. 53 | 54 | "All the parentheses" was actually not a big deal. Instead, the first 55 | mind warp was functional programming. Before long I wrapped my brain 56 | around it, and went on to become comfortable and effective with many 57 | other aspects and features of Racket. 58 | 59 | But two final frontiers remained: Macros and continuations. 60 | 61 | I found that simple macros were easy and understandable, plus there 62 | were many good tutorials available. But the moment I stepped past 63 | routine pattern-matching, I kind of fell off a cliff into a 64 | terminology soup. I marinaded myself in material, hoping it would 65 | eventually sink in after enough re-readings. I even found myself using 66 | trial and error, rather than having a clear mental model what was 67 | going on. Gah. 68 | 69 | I'm starting to write this at the point where the shapes are slowly 70 | emerging from the fog. 71 | 72 | @margin-note{If you have any corrections, criticisms, complaints, or whatever, 73 | @hyperlink["https://github.com/greghendershott/fear-of-macros/issues" "please 74 | let me know"].} 75 | 76 | My primary motive is selfish. Explaining something forces me to learn 77 | it more thoroughly. Plus if I write something with mistakes, other 78 | people will be eager to point them out and correct me. Is that a 79 | social-engineering variation of meta-programming? Next question, 80 | please. :) 81 | 82 | Finally I do hope it may help other people who have a similar 83 | background and/or learning style as me. 84 | 85 | I want to show how Racket macro features have evolved as solutions to 86 | problems or annoyances. I learn more quickly and deeply when I 87 | discover the answer to a question I already have, or find the solution 88 | to a problem whose pain I already feel. Therefore I'll give you the 89 | questions and problems first, so that you can better appreciate and 90 | understand the answers and solutions. 91 | 92 | @; ---------------------------------------------------------------------------- 93 | 94 | @section{Our plan of attack} 95 | 96 | The macro system you will mostly want to use for production-quality 97 | macros is called @racket[syntax-parse]. And don't worry, we'll get to 98 | that soon. 99 | 100 | But if we start there, you're likely to feel overwhelmed by concepts 101 | and terminology, and get very confused. I did. 102 | 103 | 1. Instead let's start with the basics: A syntax object and a function 104 | to change it---a "transformer". We'll work at that level for a while to 105 | get comfortable and to de-mythologize this whole macro business. 106 | 107 | 2. Soon we'll realize that pattern-matching would make life 108 | easier. We'll learn about @racket[syntax-case] and its shorthand 109 | cousin, @racket[define-syntax-rule]. We'll discover we can get 110 | confused if we want to munge pattern variables before sticking them 111 | back in the template, and learn how to do that. 112 | 113 | 3. At this point we'll be able to write many useful macros. But, what 114 | if we want to write the ever-popular anaphoric if, with a "magic 115 | variable"? It turns out we've been protected from making certain kind 116 | of mistakes. When we want to do this kind of thing on purpose, we use 117 | a syntax parameter. [There are other, older ways to do this. We won't 118 | look at them. We also won't spend a lot of time 119 | advocating "hygiene"---we'll just stipulate that it's good.] 120 | 121 | 4. Finally, we'll realize that our macros could be smarter when 122 | they're used in error. Normal Racket functions optionally can have 123 | contracts and types. These catch usage mistakes and provide clear, 124 | useful error messages. It would be great if there were something 125 | similar for macro. There is. One of the more-recent Racket macro 126 | enhancements is @racket[syntax-parse]. 127 | 128 | 129 | @; ---------------------------------------------------------------------------- 130 | @; ---------------------------------------------------------------------------- 131 | 132 | @section{Transform!} 133 | 134 | @verbatim[#:indent 2]{ 135 | YOU ARE INSIDE A ROOM. 136 | THERE ARE KEYS ON THE GROUND. 137 | THERE IS A SHINY BRASS LAMP NEARBY. 138 | 139 | IF YOU GO THE WRONG WAY, YOU WILL BECOME 140 | HOPELESSLY LOST AND CONFUSED. 141 | 142 | > pick up the keys 143 | 144 | YOU HAVE A SYNTAX TRANSFORMER 145 | } 146 | 147 | 148 | @subsection{What is a syntax transformer?} 149 | 150 | A syntax transformer is not one of the トランスフォーマ 151 | @hyperlink["http://en.wikipedia.org/wiki/Transformers" "transformers"]. 152 | 153 | Instead, it is simply a function. The function takes syntax and 154 | returns syntax. It transforms syntax. 155 | 156 | Here's a transformer function that ignores its input syntax, and 157 | always outputs syntax for a string literal: 158 | 159 | @margin-note{These examples assume @litchar{#lang racket}. If you want 160 | to try them using @litchar{#lang racket/base}, you'll need to 161 | @litchar{(require (for-syntax racket/base))}.} 162 | 163 | @(let-syntax([syntax (make-element-id-transformer 164 | (lambda (stx) 165 | #'@racket[syntax]))]) ;print as syntax not #' 166 | @i[ 167 | (define-syntax foo 168 | (lambda (stx) 169 | (syntax "I am foo"))) 170 | ] 171 | ) 172 | 173 | Using it: 174 | 175 | @i[ 176 | (foo) 177 | ] 178 | 179 | When we use @racket[define-syntax], we're making a transformer 180 | @italic{binding}. This tells the Racket compiler, "Whenever you 181 | encounter a chunk of syntax starting with @racket[foo], please give it 182 | to my transformer function, and replace it with the syntax I give back 183 | to you." So Racket will give anything that looks like @racket[(foo 184 | ...)] to our function, and we can return new syntax to use 185 | instead. Much like a search-and-replace. 186 | 187 | Maybe you know that the usual way to define a function in Racket: 188 | 189 | @racketblock[(define (f x) ...)] 190 | 191 | is shorthand for: 192 | 193 | @racketblock[(define f (lambda (x) ...))] 194 | 195 | That shorthand lets you avoid typing @racket[lambda] and some parentheses. 196 | 197 | Well there is a similar shorthand for @racket[define-syntax]: 198 | 199 | @(let-syntax([syntax (make-element-id-transformer 200 | (lambda (stx) 201 | #'@racket[syntax]))]) ;print as syntax not #' 202 | @i[ 203 | (define-syntax (also-foo stx) 204 | (syntax "I am also foo")) 205 | (also-foo) 206 | ] 207 | ) 208 | 209 | What we want to remember is that this is simply shorthand. We are 210 | still defining a transformer function, which takes syntax and returns 211 | syntax. Everything we do with macros, will be built on top of this 212 | basic idea. It's not magic. 213 | 214 | Speaking of shorthand, there is also a shorthand for @racket[syntax], 215 | which is @litchar{#'}: 216 | 217 | @margin-note{@litchar{#'} is short for @racket[syntax] much like 218 | @litchar{'} is short for @racket[quote].} 219 | 220 | @i[ 221 | (define-syntax (quoted-foo stx) 222 | #'"I am also foo, using #' instead of syntax") 223 | (quoted-foo) 224 | ] 225 | 226 | We'll use the @litchar{#'} shorthand from now on. 227 | 228 | Of course, we can emit syntax that is more interesting than a 229 | string literal. How about returning @racket[(displayln "hi")]? 230 | 231 | @i[ 232 | (define-syntax (say-hi stx) 233 | #'(displayln "hi")) 234 | (say-hi) 235 | ] 236 | 237 | When Racket expands our program, it sees the occurrence of 238 | @racket[(say-hi)], and sees it has a transformer function for that. It 239 | calls our function with the old syntax, and we return the new syntax, 240 | which is used to evaluate and run our program. 241 | 242 | @; ---------------------------------------------------------------------------- 243 | 244 | @subsection{What's the input?} 245 | 246 | Our examples so far have ignored the input syntax and output some 247 | fixed syntax. But typically we will want to transform the input syntax 248 | into something else. 249 | 250 | Let's start by looking closely at what the input actually @italic{is}: 251 | 252 | @i[ 253 | (define-syntax (show-me stx) 254 | (print stx) 255 | #'(void)) 256 | (show-me '(+ 1 2)) 257 | ] 258 | 259 | The @racket[(print stx)] shows what our transformer is given: a syntax 260 | object. 261 | 262 | A syntax object consists of several things. The first part is the 263 | S-expression representing the code, such as @racket['(+ 1 2)]. 264 | 265 | Racket syntax is also decorated with some interesting information such 266 | as the source file, line number, and column. Finally, it has 267 | information about lexical scoping (which you don't need to worry about 268 | now, but will turn out to be important later.) 269 | 270 | There are a variety of functions available to access a syntax object. 271 | Let's define a piece of syntax: 272 | 273 | @i[ 274 | (define stx #'(if x (list "true") #f)) 275 | stx 276 | ] 277 | 278 | Now let's use functions that access the syntax object. The source 279 | information functions are: 280 | 281 | @margin-note{@racket[(syntax-source stx)] is returning @racket['eval], 282 | only because of how I'm generating this documentation, using an 283 | evaluator to run code snippets in Scribble. Normally this would be 284 | something like "my-file.rkt".} 285 | 286 | @i[ 287 | (syntax-source stx) 288 | (syntax-line stx) 289 | (syntax-column stx) 290 | ] 291 | 292 | More interesting is the syntax "stuff" itself. @racket[syntax->datum] 293 | converts it completely into an S-expression: 294 | 295 | @i[ 296 | (syntax->datum stx) 297 | ] 298 | 299 | Whereas @racket[syntax-e] only goes "one level down". It may return a 300 | list that has syntax objects: 301 | 302 | @i[ 303 | (syntax-e stx) 304 | ] 305 | 306 | Each of those syntax objects could be converted by @racket[syntax-e], 307 | and so on recursively---which is what @racket[syntax->datum] does. 308 | 309 | In most cases, @racket[syntax->list] gives the same result as 310 | @racket[syntax-e]: 311 | 312 | @i[ 313 | (syntax->list stx) 314 | ] 315 | 316 | (When would @racket[syntax-e] and @racket[syntax->list] differ? Let's 317 | not get side-tracked now.) 318 | 319 | When we want to transform syntax, we'll generally take the pieces we 320 | were given, maybe rearrange their order, perhaps change some of the 321 | pieces, and often introduce brand-new pieces. 322 | 323 | 324 | @; ---------------------------------------------------------------------------- 325 | 326 | @subsection{Actually transforming the input} 327 | 328 | Let's write a transformer function that reverses the syntax it was 329 | given: 330 | 331 | @margin-note{The @racket[values] at the end of the example allows the 332 | result to evaluate nicely. Try 333 | @racket[(reverse-me "backwards" "am" "i")] to see why it's handy.} 334 | @i[ 335 | (define-syntax (reverse-me stx) 336 | (datum->syntax stx (reverse (cdr (syntax->datum stx))))) 337 | (reverse-me "backwards" "am" "i" values) 338 | ] 339 | 340 | Understand Yoda, we can. Great, but how does this work? 341 | 342 | First we take the input syntax, and give it to 343 | @racket[syntax->datum]. This converts the syntax into a plain old 344 | list: 345 | 346 | @i[ 347 | (syntax->datum #'(reverse-me "backwards" "am" "i" values)) 348 | ] 349 | 350 | Using @racket[cdr] slices off the first item of the list, 351 | @racket[reverse-me], leaving the remainder: 352 | @racket[("backwards" "am" "i" values)]. Passing that to 353 | @racket[reverse] changes it to @racket[(values "i" "am" "backwards")]: 354 | 355 | @i[ 356 | (reverse (cdr '(reverse-me "backwards" "am" "i" values))) 357 | ] 358 | 359 | Finally we use @racket[datum->syntax] to convert this back to 360 | @racket[syntax]: 361 | 362 | @i[ 363 | (datum->syntax #f '(values "i" "am" "backwards")) 364 | ] 365 | 366 | That's what our transformer function gives back to the Racket 367 | compiler, and @italic{that} syntax is evaluated: 368 | 369 | @i[ 370 | (values "i" "am" "backwards") 371 | ] 372 | 373 | @margin-note{The first argument of @racket[datum->syntax] contains the lexical 374 | context information that we want to associate with the @racket[syntax] 375 | outputted by the transformer. If the first argument is set to @racket[#f] then 376 | no lexical context will be associated.} 377 | 378 | @; ---------------------------------------------------------------------------- 379 | 380 | @subsection{Compile time vs. run time} 381 | 382 | @codeblock0{ 383 | (define-syntax (foo stx) 384 | (make-pipe) ;Ce n'est pas le temps d'exécution 385 | #'(void)) 386 | } 387 | 388 | Normal Racket code runs at ... run time. Duh. 389 | 390 | @margin-note{Instead of "compile time vs. run time", you may hear it 391 | described as "syntax phase vs. runtime phase". Same difference.} 392 | 393 | But a syntax transformer is called by Racket as part of the process of 394 | parsing, expanding, and compiling our program. In other words, our 395 | syntax transformer function is evaluated at compile time. 396 | 397 | This aspect of macros lets you do things that simply aren't possible 398 | in normal code. One of the classic examples is something like the 399 | Racket form, @racket[if]: 400 | 401 | @racket[(if )] 402 | 403 | If we implemented @racket[if] as a function, all of the arguments 404 | would be evaluated before being provided to the function. 405 | 406 | @i[ 407 | (define (our-if condition true-expr false-expr) 408 | (cond [condition true-expr] 409 | [else false-expr])) 410 | (our-if #t 411 | "true" 412 | "false") 413 | ] 414 | 415 | That seems to work. However, how about this: 416 | 417 | @i[ 418 | (define (display-and-return x) 419 | (displayln x) 420 | x) 421 | (our-if #t 422 | (display-and-return "true") 423 | (display-and-return "false")) 424 | ] 425 | 426 | @margin-note{One answer is that functional programming is good, and 427 | side-effects are bad. But avoiding side-effects isn't always 428 | practical.} 429 | 430 | Oops. Because the expressions have a side-effect, it's obvious that 431 | they are both evaluated. And that could be a problem---what if the 432 | side-effect includes deleting a file on disk? You wouldn't want 433 | @racket[(if user-wants-file-deleted? (delete-file) (void))] to delete 434 | a file even when @racket[user-wants-file-deleted?] is @racket[#f]. 435 | 436 | So this simply can't work as a plain function. However a syntax 437 | transformer can rearrange the syntax -- rewrite the code -- at compile 438 | time. The pieces of syntax are moved around, but they aren't actually 439 | evaluated until run time. 440 | 441 | Here is one way to do this: 442 | 443 | @i[ 444 | (define-syntax (our-if-v2 stx) 445 | (define xs (syntax->list stx)) 446 | (datum->syntax stx `(cond [,(cadr xs) ,(caddr xs)] 447 | [else ,(cadddr xs)]))) 448 | (our-if-v2 #t 449 | (display-and-return "true") 450 | (display-and-return "false")) 451 | (our-if-v2 #f 452 | (display-and-return "true") 453 | (display-and-return "false")) 454 | ] 455 | 456 | That gave the right answer. But how? Let's pull out the transformer 457 | function itself, and see what it did. We start with an example of some 458 | input syntax: 459 | 460 | @i[ 461 | (define stx (syntax (our-if-v2 #t "true" "false"))) 462 | (displayln stx) 463 | ] 464 | 465 | 1. We take the original syntax, and use @racket[syntax->list] to 466 | change it into a @racket[list] of syntax objects: 467 | 468 | @i[ 469 | (define xs (syntax->list stx)) 470 | (displayln xs) 471 | ] 472 | 473 | 2. To change this into a Racket @racket[cond] form, we need to take 474 | the three interesting pieces---the condition, true-expression, and 475 | false-expression---from the list using @racket[cadr], @racket[caddr], 476 | and @racket[cadddr] and arrange them into a @racket[cond] form: 477 | 478 | @racketblock[ 479 | `(cond [,(cadr xs) ,(caddr xs)] 480 | [else ,(cadddr xs)]) 481 | ] 482 | 483 | 3. Finally, we change that into @racket[syntax] using 484 | @racket[datum->syntax]: 485 | 486 | @i[ 487 | (datum->syntax stx `(cond [,(cadr xs) ,(caddr xs)] 488 | [else ,(cadddr xs)])) 489 | ] 490 | 491 | So that works, but using @racket[cadddr] etc. to destructure a list is 492 | painful and error-prone. Maybe you know Racket's @racket[match]? 493 | Using that would let us do pattern-matching. 494 | 495 | @margin-note{Notice that we don't care about the first item in the 496 | syntax list. We didn't take @racket[(car xs)] in our-if-v2, and we 497 | didn't use @racket[name] when we used pattern-matching. In general, a 498 | syntax transformer won't care about that, because it is the name of 499 | the transformer binding. In other words, a macro usually doesn't care 500 | about its own name.} 501 | 502 | Instead of: 503 | 504 | @i[ 505 | (define-syntax (our-if-v2 stx) 506 | (define xs (syntax->list stx)) 507 | (datum->syntax stx `(cond [,(cadr xs) ,(caddr xs)] 508 | [else ,(cadddr xs)]))) 509 | ] 510 | 511 | We can write: 512 | 513 | @i[ 514 | (define-syntax (our-if-using-match stx) 515 | (match (syntax->list stx) 516 | [(list name condition true-expr false-expr) 517 | (datum->syntax stx `(cond [,condition ,true-expr] 518 | [else ,false-expr]))]))] 519 | 520 | Great. Now let's try using it: 521 | 522 | @i[ 523 | (our-if-using-match #t "true" "false") 524 | ] 525 | 526 | Oops. It's complaining that @racket[match] isn't defined. 527 | 528 | Our transformer function is working at compile time, not run time. And 529 | at compile time, only @racket[racket/base] is required for you 530 | automatically---not the full @racket[racket]. 531 | 532 | Anything beyond @racket[racket/base], we have to require 533 | ourselves---and require it for compile time using the 534 | @racket[for-syntax] form of @racket[require]. 535 | 536 | In this case, instead of using plain @racket[(require racket/match)], 537 | we want @racket[(require (for-syntax racket/match))]---the 538 | @racket[for-syntax] part meaning, "for compile time". 539 | 540 | So let's try that: 541 | 542 | @i[ 543 | (require (for-syntax racket/match)) 544 | (define-syntax (our-if-using-match-v2 stx) 545 | (match (syntax->list stx) 546 | [(list _ condition true-expr false-expr) 547 | (datum->syntax stx `(cond [,condition ,true-expr] 548 | [else ,false-expr]))])) 549 | (our-if-using-match-v2 #t "true" "false") 550 | ] 551 | 552 | Joy. 553 | 554 | @; ---------------------------------------------------------------------------- 555 | 556 | @subsection{@racket[begin-for-syntax]} 557 | 558 | We used @racket[for-syntax] to @racket[require] the 559 | @racket[racket/match] module because we needed to use @racket[match] 560 | at compile time. 561 | 562 | What if we wanted to define our own helper function to be used by a 563 | macro? One way to do that is put it in another module, and 564 | @racket[require] it using @racket[for-syntax], just like we did with 565 | the @racket[racket/match] module. 566 | 567 | If instead we want to put the helper in the same module, we can't 568 | simply @racket[define] it and use it---the definition would exist at 569 | run time, but we need it at compile time. The answer is to put the 570 | definition of the helper function(s) inside @racket[begin-for-syntax]: 571 | 572 | @racketblock[ 573 | (begin-for-syntax 574 | (define (my-helper-function ....) 575 | ....)) 576 | (define-syntax (macro-using-my-helper-function stx) 577 | (my-helper-function ....) 578 | ....) 579 | ] 580 | 581 | In the simple case, we can also use @racket[define-for-syntax], which 582 | composes @racket[begin-for-syntax] and @racket[define]: 583 | 584 | @racketblock[ 585 | (define-for-syntax (my-helper-function ....) 586 | ....) 587 | (define-syntax (macro-using-my-helper-function stx) 588 | (my-helper-function ....) 589 | ....) 590 | ] 591 | 592 | To review: 593 | 594 | @itemize[ 595 | 596 | @item{Syntax transformers work at compile time, not run time. The good 597 | news is this means we can do things like rearrange the pieces of 598 | syntax without evaluating them. We can implement forms like 599 | @racket[if] that simply couldn't work properly as run time functions.} 600 | 601 | @item{More good news is that there isn't some special, weird language 602 | for writing syntax transformers. We can write these transformer 603 | functions using the Racket language we already know and love.} 604 | 605 | @item{The semi-bad news is that the familiarity can make it easy to forget 606 | that we're not working at run time. Sometimes that's important to 607 | remember. 608 | 609 | @itemize[ 610 | 611 | @item{For example only @racket[racket/base] is required for us 612 | automatically. If we need other modules, we have to require them, and 613 | do so @italic{for compile time} using @racket[for-syntax].} 614 | 615 | @item{Similarly, if we want to define helper functions in the same 616 | file/module as the macros that use them, we need to wrap the 617 | definitions inside a @racket[begin-for-syntax] form. Doing so makes 618 | them available at compile time.} 619 | 620 | ] 621 | } 622 | ] 623 | 624 | @; ---------------------------------------------------------------------------- 625 | @; ---------------------------------------------------------------------------- 626 | 627 | @section[#:tag "pattern-matching"]{Pattern matching: syntax-case and syntax-rules} 628 | 629 | Most useful syntax transformers work by taking some input syntax, and 630 | rearranging the pieces into something else. As we saw, this is 631 | possible but tedious using list accessors such as 632 | @racket[cadddr]. It's more convenient and less error-prone to use 633 | @racket[match] to do pattern-matching. 634 | 635 | @margin-note{Historically, @racket[syntax-case] and 636 | @racket[syntax-rules] pattern matching came first. @racket[match] was 637 | added to Racket later.} 638 | 639 | It turns out that pattern-matching was one of the first improvements 640 | to be added to the Racket macro system. It's called 641 | @racket[syntax-case], and has a shorthand for simple situations called 642 | @racket[define-syntax-rule]. 643 | 644 | Recall our previous example: 645 | 646 | @racketblock[ 647 | (require (for-syntax racket/match)) 648 | (define-syntax (our-if-using-match-v2 stx) 649 | (match (syntax->list stx) 650 | [(list _ condition true-expr false-expr) 651 | (datum->syntax stx `(cond [,condition ,true-expr] 652 | [else ,false-expr]))])) 653 | ] 654 | 655 | Here's what it looks like using @racket[syntax-case]: 656 | 657 | @i[ 658 | (define-syntax (our-if-using-syntax-case stx) 659 | (syntax-case stx () 660 | [(_ condition true-expr false-expr) 661 | #'(cond [condition true-expr] 662 | [else false-expr])])) 663 | (our-if-using-syntax-case #t "true" "false") 664 | ] 665 | 666 | Pretty similar, huh? The pattern matching part looks almost exactly 667 | the same. The way we specify the new syntax is simpler. We don't need 668 | to do quasi-quoting and unquoting. We don't need to use 669 | @racket[datum->syntax]. Instead, we supply a "template", which uses 670 | variables from the pattern. 671 | 672 | There is a shorthand for simple pattern-matching cases, which expands 673 | into @racket[syntax-case]. It's called @racket[define-syntax-rule]: 674 | 675 | @i[ 676 | (define-syntax-rule (our-if-using-syntax-rule condition true-expr false-expr) 677 | (cond [condition true-expr] 678 | [else false-expr])) 679 | (our-if-using-syntax-rule #t "true" "false") 680 | ] 681 | 682 | Here's the thing about @racket[define-syntax-rule]. Because it's so 683 | simple, @racket[define-syntax-rule] is often the first thing people are 684 | taught about macros. But it's almost deceptively simple. It looks so 685 | much like defining a normal run time function---yet it's not. It's 686 | working at compile time, not run time. Worse, the moment you want to 687 | do more than @racket[define-syntax-rule] can handle, you can fall off 688 | a cliff into what feels like complicated and confusing 689 | territory. Hopefully, because we started with a basic syntax 690 | transformer, and worked up from that, we won't have that problem. We 691 | can appreciate @racket[define-syntax-rule] as a convenient shorthand, 692 | but not be scared of, or confused about, that for which it's 693 | shorthand. 694 | 695 | Most of the materials I found for learning macros, including the 696 | Racket @italic{Guide}, do a very good job explaining 697 | @hyperlink["http://docs.racket-lang.org/guide/pattern-macros.html" "how 698 | patterns and templates work"]. So I won't regurgitate that here. 699 | 700 | Sometimes, we need to go a step beyond the pattern and template. Let's 701 | look at some examples, how we can get confused, and how to get it 702 | working. 703 | 704 | @; ---------------------------------------------------------------------------- 705 | 706 | @subsection{Pattern variable vs. template---fight!} 707 | 708 | Let's say we want to define a function with a hyphenated name, a-b, 709 | but we supply the a and b parts separately. The Racket @racket[struct] 710 | macro does something like this: @racket[(struct foo (field1 field2))] 711 | automatically defines a number of functions whose names are variations 712 | on the name @racket[foo]---such as @racket[foo-field1], 713 | @racket[foo-field2], @racket[foo?], and so on. 714 | 715 | So let's pretend we're doing something like that. We want to transform 716 | the syntax @racket[(hyphen-define a b (args) body)] to the syntax 717 | @racket[(define (a-b args) body)]. 718 | 719 | A wrong first attempt is: 720 | 721 | @i[ 722 | (define-syntax (hyphen-define/wrong1 stx) 723 | (syntax-case stx () 724 | [(_ a b (args ...) body0 body ...) 725 | (let ([name (string->symbol (format "~a-~a" a b))]) 726 | #'(define (name args ...) 727 | body0 body ...))])) 728 | ] 729 | 730 | Huh. We have no idea what this error message means. Well, let's try to 731 | work it out. The "template" the error message refers to is the 732 | @racket[#'(define (name args ...) body0 body ...)] portion. The 733 | @racket[let] isn't part of that template. It sounds like we can't use 734 | @racket[a] (or @racket[b]) in the @racket[let] part. 735 | 736 | In fact, @racket[syntax-case] can have as many templates as you 737 | want. The obvious, required template is the final expression supplying 738 | the output syntax. But you can use @racket[syntax] (a.k.a. @litchar{#'}) on a 739 | pattern variable. This makes another template, albeit a small, "fun 740 | size" template. Let's try that: 741 | 742 | @i[ 743 | (define-syntax (hyphen-define/wrong1.1 stx) 744 | (syntax-case stx () 745 | [(_ a b (args ...) body0 body ...) 746 | (let ([name (string->symbol (format "~a-~a" #'a #'b))]) 747 | #'(define (name args ...) 748 | body0 body ...))])) 749 | ] 750 | 751 | No more errors---good! Let's try to use it: 752 | 753 | @i[ 754 | (hyphen-define/wrong1.1 foo bar () #t) 755 | (foo-bar) 756 | ] 757 | 758 | Apparently our macro is defining a function with some name other than 759 | @racket[foo-bar]. Huh. 760 | 761 | This is where the Macro Stepper in DrRacket is 762 | invaluable. @margin-note{Even if you prefer mostly to use Emacs, this 763 | is a situation where it's definitely worth temporarily using DrRacket 764 | for its Macro Stepper.} 765 | 766 | @image[#:scale 0.5 "macro-stepper.png"] 767 | 768 | The Macro Stepper says that the use of our macro: 769 | 770 | @racketblock[ 771 | (hyphen-define/wrong1.1 foo bar () #t) 772 | ] 773 | 774 | expanded to: 775 | 776 | @racketblock[ 777 | (define (name) #t) 778 | ] 779 | 780 | Well that explains it. Instead, we wanted to expand to: 781 | 782 | @racketblock[ 783 | (define (foo-bar) #t) 784 | ] 785 | 786 | Our template is using the symbol @racket[name] but we wanted its 787 | value, such as @racket[foo-bar] in this use of our macro. 788 | 789 | Is there anything we already know that behaves like this---where using 790 | a variable in the template yields its value? Yes: Pattern 791 | variables. Our pattern doesn't include @racket[name] because we don't 792 | expect it in the original syntax---indeed the whole point of this 793 | macro is to create it. So @racket[name] can't be in the main 794 | pattern. Fine---let's make an @italic{additional} pattern. We can do 795 | that using an additional, nested @racket[syntax-case]: 796 | 797 | @i[ 798 | (define-syntax (hyphen-define/wrong1.2 stx) 799 | (syntax-case stx () 800 | [(_ a b (args ...) body0 body ...) 801 | (syntax-case (datum->syntax #'a 802 | (string->symbol (format "~a-~a" #'a #'b))) 803 | () 804 | [name #'(define (name args ...) 805 | body0 body ...)])])) 806 | ] 807 | 808 | Looks weird? Let's take a deep breath. Normally our transformer 809 | function is given syntax by Racket, and we pass that syntax to 810 | @racket[syntax-case]. But we can also create some syntax of our own, 811 | on the fly, and pass @italic{that} to @racket[syntax-case]. That's all 812 | we're doing here. The whole @racket[(datum->syntax ...)] expression is 813 | syntax that we're creating on the fly. We can give that to 814 | @racket[syntax-case], and match it using a pattern variable named 815 | @racket[name]. Voila, we have a new pattern variable. We can use it in 816 | a template, and its value will go in the template. 817 | 818 | We might have one more---just one, I promise!---small problem left. 819 | Let's try to use our new version: 820 | 821 | @i[ 822 | (hyphen-define/wrong1.2 foo bar () #t) 823 | (foo-bar) 824 | ] 825 | 826 | Hmm. @racket[foo-bar] is @italic{still} not defined. Back to the Macro 827 | Stepper. It says now we're expanding to: 828 | 829 | @racketblock[(define (|#-#|) #t)] 830 | 831 | Oh right: @racket[#'a] and @racket[#'b] are syntax objects. Therefore 832 | 833 | @racketblock[(string->symbol (format "~a-~a" #'a #'b))] 834 | 835 | is the printed form of both syntax objects, joined by a hyphen: 836 | 837 | @racketblock[|#-#|] 838 | 839 | Instead we want the datum in the syntax objects, such as the symbols 840 | @racket[foo] and @racket[bar]. Which we get using 841 | @racket[syntax->datum]: 842 | 843 | @i[ 844 | (define-syntax (hyphen-define/ok1 stx) 845 | (syntax-case stx () 846 | [(_ a b (args ...) body0 body ...) 847 | (syntax-case (datum->syntax #'a 848 | (string->symbol (format "~a-~a" 849 | (syntax->datum #'a) 850 | (syntax->datum #'b)))) 851 | () 852 | [name #'(define (name args ...) 853 | body0 body ...)])])) 854 | (hyphen-define/ok1 foo bar () #t) 855 | (foo-bar) 856 | ] 857 | 858 | And now it works! 859 | 860 | Next, some shortcuts. 861 | 862 | @subsubsection{@racket[with-syntax]} 863 | 864 | Instead of an additional, nested @racket[syntax-case], we could use 865 | @racket[with-syntax]@margin-note*{Another name for 866 | @racket[with-syntax] could be, "with new pattern variable".}. This 867 | rearranges the @racket[syntax-case] to look more like a @racket[let] 868 | statement---first the name, then the value. Also it's more convenient 869 | if we need to define more than one pattern variable. 870 | 871 | @i[ 872 | (define-syntax (hyphen-define/ok2 stx) 873 | (syntax-case stx () 874 | [(_ a b (args ...) body0 body ...) 875 | (with-syntax ([name (datum->syntax #'a 876 | (string->symbol (format "~a-~a" 877 | (syntax->datum #'a) 878 | (syntax->datum #'b))))]) 879 | #'(define (name args ...) 880 | body0 body ...))])) 881 | (hyphen-define/ok2 foo bar () #t) 882 | (foo-bar) 883 | ] 884 | 885 | Again, @racket[with-syntax] is simply @racket[syntax-case] rearranged: 886 | 887 | @racketblock[ 888 | (syntax-case #,(italic "") () [#,(bold "") ]) 889 | (with-syntax ([#,(bold "") #,(italic "")]) ) 890 | ] 891 | 892 | Whether you use an additional @racket[syntax-case] or use 893 | @racket[with-syntax], either way you are simply defining additional 894 | pattern variables. Don't let the terminology and structure make it 895 | seem mysterious. 896 | 897 | @subsubsection{@racket[with-syntax*]} 898 | 899 | We know that @racket[let] doesn't let us use a binding in a subsequent 900 | one: 901 | 902 | @i[ 903 | (let ([a 0] 904 | [b a]) 905 | b) 906 | ] 907 | 908 | Instead we can nest @racket[let]s: 909 | 910 | @i[ 911 | (let ([a 0]) 912 | (let ([b a]) 913 | b)) 914 | ] 915 | 916 | Or use a shorthand for nesting, @racket[let*]: 917 | 918 | @i[ 919 | (let* ([a 0] 920 | [b a]) 921 | b) 922 | ] 923 | 924 | Similarly, instead of writing nested @racket[with-syntax]s, we can use 925 | @racket[with-syntax*]: 926 | 927 | @i[ 928 | (require (for-syntax racket/syntax)) 929 | (define-syntax (foo stx) 930 | (syntax-case stx () 931 | [(_ a) 932 | (with-syntax* ([b #'a] 933 | [c #'b]) 934 | #'c)])) 935 | ] 936 | 937 | One gotcha is that @racket[with-syntax*] isn't provided by 938 | @racket[racket/base]. We must @racket[(require (for-syntax 939 | racket/syntax))]. Otherwise we may get a rather bewildering error 940 | message: 941 | 942 | @italic{@tt{...: ellipses not allowed as an expression in: ...}}. 943 | 944 | 945 | @subsubsection{@racket[format-id]} 946 | 947 | There is a utility function in @racket[racket/syntax] called 948 | @racket[format-id] that lets us format identifier names more 949 | succinctly than what we did above: 950 | 951 | @i[ 952 | (require (for-syntax racket/syntax)) 953 | (define-syntax (hyphen-define/ok3 stx) 954 | (syntax-case stx () 955 | [(_ a b (args ...) body0 body ...) 956 | (with-syntax ([name (format-id #'a "~a-~a" #'a #'b)]) 957 | #'(define (name args ...) 958 | body0 body ...))])) 959 | (hyphen-define/ok3 bar baz () #t) 960 | (bar-baz) 961 | ] 962 | 963 | Using @racket[format-id] is convenient as it handles the tedium of 964 | converting from syntax to symbol datum to string ... and all the way 965 | back. 966 | 967 | The first argument of @racket[format-id], @racket[lctx], is the 968 | lexical context of the identifier that will be created. You almost 969 | never want to supply @racket[stx]---the overall chunk of syntax that 970 | the macro transforms. Instead you want to supply some more-specific 971 | bit of syntax, such as an identifier that the user has provided to the 972 | macro. In this example, we're using @racket[#'a]. The resulting 973 | identifier will have the same scope as that which the user provided. 974 | This is more likely to behave as the user expects, especially when our 975 | macro is composed with other macros. 976 | 977 | @subsubsection{Another example} 978 | 979 | Finally, here's a variation that accepts an arbitrary number of name 980 | parts to be joined with hyphens: 981 | 982 | @i[ 983 | (require (for-syntax racket/string racket/syntax)) 984 | (define-syntax (hyphen-define* stx) 985 | (syntax-case stx () 986 | [(_ (names ...) (args ...) body0 body ...) 987 | (let ([name-stxs (syntax->list #'(names ...))]) 988 | (with-syntax ([name (datum->syntax (car name-stxs) 989 | (string->symbol 990 | (string-join (for/list ([name-stx name-stxs]) 991 | (symbol->string 992 | (syntax-e name-stx))) 993 | "-")))]) 994 | #'(define (name args ...) 995 | body0 body ...)))])) 996 | (hyphen-define* (foo bar baz) (v) (* 2 v)) 997 | (foo-bar-baz 50) 998 | ] 999 | 1000 | Just as when we used @racket[format-id], when using 1001 | @racket[datum->syntax] we're being careful with the first, 1002 | @racket[lctx] argument. We want the identifier we create to use the 1003 | lexical context of an identifier provided to the macro by the user. In 1004 | this case, the user's identifiers are in the @racket[(names ...)] 1005 | template variable. We change this from one @racket[syntax] into a 1006 | @racket[list] of @racket[syntax]es. The first element we use for the 1007 | lexical context. Then of course we'll use all the elements to form the 1008 | hyphenated identifier. 1009 | 1010 | To review: 1011 | 1012 | @itemize[ 1013 | 1014 | @item{You can't use a pattern variable outside of a template. But 1015 | you can use @racket[syntax] or @litchar{#'} on a pattern variable to make 1016 | an ad hoc, "fun size" template.} 1017 | 1018 | @item{If you want to munge pattern variables for use in the 1019 | template, @racket[with-syntax] is your friend, because it lets you 1020 | create new pattern variables.} 1021 | 1022 | @item{Usually you'll need to use @racket[syntax->datum] to get the 1023 | interesting value inside.} 1024 | 1025 | @item{@racket[format-id] is convenient for formatting identifier 1026 | names.} 1027 | 1028 | ] 1029 | 1030 | @; ---------------------------------------------------------------------------- 1031 | 1032 | @subsection{Making our own @racket[struct]} 1033 | 1034 | Let's apply what we just learned to a more-realistic example. We'll 1035 | pretend that Racket doesn't already have a @racket[struct] 1036 | capability. Fortunately, we can write a macro to provide our own 1037 | system for defining and using structures. To keep things simple, our 1038 | structure will be immutable (read-only) and it won't support 1039 | inheritance. 1040 | 1041 | Given a structure declaration like: 1042 | 1043 | @racketblock[ 1044 | (our-struct name (field1 field2 ...)) 1045 | ] 1046 | 1047 | We need to define some procedures: 1048 | 1049 | @itemize[ 1050 | 1051 | @item{A constructor procedure whose name is the struct name. We'll 1052 | represent structures as a @racket[vector]. The structure name will be 1053 | element zero. The fields will be elements one onward.} 1054 | 1055 | @item{A predicate, whose name is the struct name with @tt{?} 1056 | appended.} 1057 | 1058 | @item{For each field, an accessor procedure to get its value. These 1059 | will be named struct-field (the name of the struct, a hyphen, and the 1060 | field name).} 1061 | 1062 | ] 1063 | 1064 | 1065 | @#reader scribble/comment-reader 1066 | (i 1067 | (require (for-syntax racket/syntax)) 1068 | (define-syntax (our-struct stx) 1069 | (syntax-case stx () 1070 | [(_ id (fields ...)) 1071 | (with-syntax ([pred-id (format-id #'id "~a?" #'id)]) 1072 | #`(begin 1073 | ;; Define a constructor. 1074 | (define (id fields ...) 1075 | (apply vector (cons (quote id) (list fields ...)))) 1076 | ;; Define a predicate. 1077 | (define (pred-id v) 1078 | (and (vector? v) 1079 | (eq? (vector-ref v 0) 'id))) 1080 | ;; Define an accessor for each field. 1081 | #,@(for/list ([x (syntax->list #'(fields ...))] 1082 | [n (in-naturals 1)]) 1083 | (with-syntax ([acc-id (format-id #'id "~a-~a" #'id x)] 1084 | [ix n]) 1085 | #`(define (acc-id v) 1086 | (unless (pred-id v) 1087 | (error 'acc-id "~a is not a ~a struct" v 'id)) 1088 | (vector-ref v ix))))))])) 1089 | 1090 | ;; Test it out 1091 | (require rackunit) 1092 | (our-struct foo (a b)) 1093 | (define s (foo 1 2)) 1094 | (check-true (foo? s)) 1095 | (check-false (foo? 1)) 1096 | (check-equal? (foo-a s) 1) 1097 | (check-equal? (foo-b s) 2) 1098 | (check-exn exn:fail? 1099 | (lambda () (foo-a "furble"))) 1100 | 1101 | ;; The tests passed. 1102 | ;; Next, what if someone tries to declare: 1103 | (our-struct "blah" ("blah" "blah")) 1104 | ) 1105 | 1106 | The error message is not very helpful. It's coming from 1107 | @racket[format-id], which is a private implementation detail of our macro. 1108 | 1109 | You may know that a @racket[syntax-case] clause can take an 1110 | optional "guard" or "fender" expression. Instead of 1111 | 1112 | @racketblock[ 1113 | [pattern template] 1114 | ] 1115 | 1116 | It can be: 1117 | 1118 | @racketblock[ 1119 | [pattern guard template] 1120 | ] 1121 | 1122 | Let's add a guard expression to our clause: 1123 | 1124 | @#reader scribble/comment-reader 1125 | (i 1126 | (require (for-syntax racket/syntax)) 1127 | (define-syntax (our-struct stx) 1128 | (syntax-case stx () 1129 | [(_ id (fields ...)) 1130 | ;; Guard or "fender" expression: 1131 | (for-each (lambda (x) 1132 | (unless (identifier? x) 1133 | (raise-syntax-error #f "not an identifier" stx x))) 1134 | (cons #'id (syntax->list #'(fields ...)))) 1135 | (with-syntax ([pred-id (format-id #'id "~a?" #'id)]) 1136 | #`(begin 1137 | ;; Define a constructor. 1138 | (define (id fields ...) 1139 | (apply vector (cons (quote id) (list fields ...)))) 1140 | ;; Define a predicate. 1141 | (define (pred-id v) 1142 | (and (vector? v) 1143 | (eq? (vector-ref v 0) 'id))) 1144 | ;; Define an accessor for each field. 1145 | #,@(for/list ([x (syntax->list #'(fields ...))] 1146 | [n (in-naturals 1)]) 1147 | (with-syntax ([acc-id (format-id #'id "~a-~a" #'id x)] 1148 | [ix n]) 1149 | #`(define (acc-id v) 1150 | (unless (pred-id v) 1151 | (error 'acc-id "~a is not a ~a struct" v 'id)) 1152 | (vector-ref v ix))))))])) 1153 | 1154 | ;; Now the same misuse gives a better error message: 1155 | (our-struct "blah" ("blah" "blah")) 1156 | ) 1157 | 1158 | Later, we'll see how @racket[syntax-parse] makes it even easier to 1159 | check usage and provide helpful messages about mistakes. 1160 | 1161 | 1162 | @subsection[#:tag "hash.refs"]{Using dot notation for nested hash lookups} 1163 | 1164 | The previous two examples used a macro to define functions whose names 1165 | were made by joining identifiers provided to the macro. This example 1166 | does the opposite: The identifier given to the macro is split into 1167 | pieces. 1168 | 1169 | If you write programs for web services you deal with JSON, which is 1170 | represented in Racket by a @racket[jsexpr?]. JSON often has 1171 | dictionaries that contain other dictionaries. In a @racket[jsexpr?] 1172 | these are represented by nested @racket[hasheq] tables: 1173 | 1174 | @#reader scribble/comment-reader 1175 | (i 1176 | ; Nested `hasheq's typical of a jsexpr: 1177 | (define js (hasheq 'a (hasheq 'b (hasheq 'c "value")))) 1178 | ) 1179 | 1180 | In JavaScript you can use dot notation: 1181 | 1182 | @codeblock{ 1183 | foo = js.a.b.c; 1184 | } 1185 | 1186 | In Racket it's not so convenient: 1187 | 1188 | @racketblock[(hash-ref (hash-ref (hash-ref js 'a) 'b) 'c)] 1189 | 1190 | We can write a helper function to make this a bit cleaner: 1191 | 1192 | @#reader scribble/comment-reader 1193 | (i 1194 | ;; This helper function: 1195 | (define/contract (hash-refs h ks [def #f]) 1196 | ((hash? (listof any/c)) (any/c) . ->* . any) 1197 | (with-handlers ([exn:fail? (const (cond [(procedure? def) (def)] 1198 | [else def]))]) 1199 | (for/fold ([h h]) 1200 | ([k (in-list ks)]) 1201 | (hash-ref h k)))) 1202 | 1203 | ;; Lets us say: 1204 | (hash-refs js '(a b c)) 1205 | ) 1206 | 1207 | That's better. Can we go even further and use a dot notation somewhat 1208 | like JavaScript? 1209 | 1210 | @#reader scribble/comment-reader 1211 | (i 1212 | ;; This macro: 1213 | (require (for-syntax racket/syntax)) 1214 | (define-syntax (hash.refs stx) 1215 | (syntax-case stx () 1216 | ;; If the optional `default' is missing, use #f. 1217 | [(_ chain) 1218 | #'(hash.refs chain #f)] 1219 | [(_ chain default) 1220 | (let* ([chain-str (symbol->string (syntax->datum #'chain))] 1221 | [ids (for/list ([str (in-list (regexp-split #rx"\\." chain-str))]) 1222 | (format-id #'chain "~a" str))]) 1223 | (with-syntax ([hash-table (car ids)] 1224 | [keys (cdr ids)]) 1225 | #'(hash-refs hash-table 'keys default)))])) 1226 | ;; Gives us "sugar" to say this: 1227 | (hash.refs js.a.b.c) 1228 | ;; Try finding a key that doesn't exist: 1229 | (hash.refs js.blah) 1230 | ;; Try finding a key that doesn't exist, specifying the default: 1231 | (hash.refs js.blah 'did-not-exist) 1232 | ) 1233 | 1234 | It works! 1235 | 1236 | We've started to appreciate that our macros should give helpful 1237 | messages when used in error. Let's try to do that here. 1238 | 1239 | @#reader scribble/comment-reader 1240 | (i 1241 | (require (for-syntax racket/syntax)) 1242 | (define-syntax (hash.refs stx) 1243 | (syntax-case stx () 1244 | ;; Check for no args at all 1245 | [(_) 1246 | (raise-syntax-error #f "Expected hash.key0[.key1 ...] [default]" stx)] 1247 | ;; If the optional `default' is missing, use #f. 1248 | [(_ chain) 1249 | #'(hash.refs chain #f)] 1250 | [(_ chain default) 1251 | (unless (identifier? #'chain) 1252 | (raise-syntax-error #f "Expected hash.key0[.key1 ...] [default]" stx #'chain)) 1253 | (let* ([chain-str (symbol->string (syntax->datum #'chain))] 1254 | [ids (for/list ([str (in-list (regexp-split #rx"\\." chain-str))]) 1255 | (format-id #'chain "~a" str))]) 1256 | ;; Check that we have at least hash.key 1257 | (unless (and (>= (length ids) 2) 1258 | (not (eq? (syntax-e (cadr ids)) '||))) 1259 | (raise-syntax-error #f "Expected hash.key" stx #'chain)) 1260 | (with-syntax ([hash-table (car ids)] 1261 | [keys (cdr ids)]) 1262 | #'(hash-refs hash-table 'keys default)))])) 1263 | 1264 | ;; See if we catch each of the misuses 1265 | (hash.refs) 1266 | (hash.refs 0) 1267 | (hash.refs js) 1268 | (hash.refs js.) 1269 | ) 1270 | 1271 | Not too bad. Of course, the version with error-checking is quite a bit 1272 | longer. Error-checking code generally tends to obscure the logic, and 1273 | does here. Fortunately we'll soon see how @racket[syntax-parse] can 1274 | help mitigate that, in much the same way as contracts in normal 1275 | Racket or types in Typed Racket. 1276 | 1277 | Maybe we're not convinced that writing @racket[(hash.refs js.a.b.c)] 1278 | is really clearer than @racket[(hash-refs js '(a b c))]. Maybe we 1279 | won't actually use this approach. But the Racket macro system makes it 1280 | a possible choice. 1281 | 1282 | @; ---------------------------------------------------------------------------- 1283 | @; ---------------------------------------------------------------------------- 1284 | 1285 | @section{Syntax parameters} 1286 | 1287 | "Anaphoric if" or "aif" is a popular macro example. Instead of writing: 1288 | 1289 | @racketblock[ 1290 | (let ([tmp (big-long-calculation)]) 1291 | (if tmp 1292 | (foo tmp) 1293 | #f)) 1294 | ] 1295 | 1296 | You could write: 1297 | 1298 | @racketblock[ 1299 | (aif (big-long-calculation) 1300 | (foo it) 1301 | #f) 1302 | ] 1303 | 1304 | In other words, when the condition is true, an @racket[it] identifier 1305 | is automatically created and set to the value of the condition. This 1306 | should be easy: 1307 | 1308 | 1309 | @i[ 1310 | (define-syntax-rule (aif condition true-expr false-expr) 1311 | (let ([it condition]) 1312 | (if it 1313 | true-expr 1314 | false-expr))) 1315 | (aif #t (displayln it) (void)) 1316 | ] 1317 | 1318 | Wait, what? @racket[it] is undefined? 1319 | 1320 | It turns out that all along we have been protected from making a 1321 | certain kind of mistake in our macros. The mistake is if our new 1322 | syntax introduces a variable that accidentally conflicts with one in 1323 | the code surrounding our macro. 1324 | 1325 | The Racket @italic{Reference} section, 1326 | @hyperlink["http://docs.racket-lang.org/reference/syntax-model.html#(part._transformer-model)" "Transformer 1327 | Bindings"], has a good explanation and example. Basically, syntax 1328 | has "marks" to preserve lexical scope. This makes your macro behave 1329 | like a normal function, for lexical scoping. 1330 | 1331 | If a normal function defines a variable named @racket[x], it won't 1332 | conflict with a variable named @racket[x] in an outer scope: 1333 | 1334 | @i[ 1335 | (let ([x "outer"]) 1336 | (let ([x "inner"]) 1337 | (printf "The inner `x' is ~s\n" x)) 1338 | (printf "The outer `x' is ~s\n" x)) 1339 | ] 1340 | 1341 | When our macros also respect lexical scoping, it's easier to write 1342 | reliable macros that behave predictably. 1343 | 1344 | So that's wonderful default behavior. But sometimes we want to 1345 | introduce a magic variable on purpose---such as @racket[it] for 1346 | @racket[aif]. 1347 | 1348 | There's a bad way to do this and a good way. 1349 | 1350 | The bad way is to use @racket[datum->syntax], which is tricky to use correctly. @margin-note*{See @hyperlink["http://www.schemeworkshop.org/2011/papers/Barzilay2011.pdf" "Keeping it Clean with Syntax Parameters (PDF)"].} 1351 | 1352 | The good way is with a syntax parameter, using 1353 | @racket[define-syntax-parameter] and 1354 | @racket[syntax-parameterize]. You're probably familiar with regular 1355 | parameters in Racket: 1356 | 1357 | @i[ 1358 | (define current-foo (make-parameter "some default value")) 1359 | (current-foo) 1360 | (parameterize ([current-foo "I have a new value, for now"]) 1361 | (current-foo)) 1362 | (current-foo) 1363 | ] 1364 | 1365 | That's a normal parameter. The syntax variation works similarly. The 1366 | idea is that we'll define @racket[it] to mean an error by 1367 | default. Only inside of our @racket[aif] will it have a meaningful 1368 | value: 1369 | 1370 | @i[ 1371 | (require racket/stxparam) 1372 | (define-syntax-parameter it 1373 | (lambda (stx) 1374 | (raise-syntax-error (syntax-e stx) "can only be used inside aif"))) 1375 | (define-syntax-rule (aif condition true-expr false-expr) 1376 | (let ([tmp condition]) 1377 | (if tmp 1378 | (syntax-parameterize ([it (make-rename-transformer #'tmp)]) 1379 | true-expr) 1380 | false-expr))) 1381 | (aif 10 (displayln it) (void)) 1382 | (aif #f (displayln it) (void)) 1383 | ] 1384 | 1385 | Inside the @racket[syntax-parameterize], @racket[it] acts as an alias 1386 | for @racket[tmp]. The alias behavior is created by 1387 | @racket[make-rename-transformer]. 1388 | 1389 | If we try to use @racket[it] outside of an @racket[aif] form, and 1390 | @racket[it] isn't otherwise defined, we get an error like we want: 1391 | 1392 | @i[ 1393 | (displayln it) 1394 | ] 1395 | 1396 | But we can still define @racket[it] as a normal variable in local 1397 | definition contexts like: 1398 | 1399 | @i[ 1400 | (let ([it 10]) 1401 | it) 1402 | ] 1403 | 1404 | or: 1405 | 1406 | @i[ 1407 | (define (foo) 1408 | (define it 10) 1409 | it) 1410 | (foo) 1411 | ] 1412 | 1413 | 1414 | For a deeper look, see @hyperlink["http://www.schemeworkshop.org/2011/papers/Barzilay2011.pdf" "Keeping it Clean with Syntax Parameters"]. 1415 | 1416 | @; ---------------------------------------------------------------------------- 1417 | @; ---------------------------------------------------------------------------- 1418 | 1419 | @section{What's the point of @racket[splicing-let]?} 1420 | 1421 | I stared at @racket[racket/splicing] for the longest time. What does 1422 | it do? Why would I use it? Why is it in the Macros section of the 1423 | reference? 1424 | 1425 | Step one, @elem[#:style "strike"]{cut a hole in the box} 1426 | de-mythologize it. For example, using @racket[splicing-let] like this: 1427 | 1428 | @#reader scribble/comment-reader 1429 | (i 1430 | (require racket/splicing) 1431 | (splicing-let ([x 0]) 1432 | (define (get-x) 1433 | x)) 1434 | ;; get-x is visible out here: 1435 | (get-x) 1436 | ;; but x is not: 1437 | x 1438 | ) 1439 | 1440 | is equivalent to: 1441 | 1442 | @#reader scribble/comment-reader 1443 | (i 1444 | (define get-y 1445 | (let ([y 0]) 1446 | (lambda () 1447 | y))) 1448 | ;; get-y is visible out here: 1449 | (get-y) 1450 | ;; but y is not: 1451 | y 1452 | ) 1453 | 1454 | This is the classic Lisp/Scheme/Racket idiom sometimes called "let 1455 | over lambda". @margin-note*{A 1456 | @hyperlink["http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html" "koan"] 1457 | about closures and objects.} A closure hides @racket[y], which can 1458 | only be accessed via @racket[get-y]. 1459 | 1460 | So why would we care about the splicing forms? They can be more 1461 | concise, especially when there are multiple body forms: 1462 | 1463 | @i[ 1464 | (require racket/splicing) 1465 | (splicing-let ([x 0]) 1466 | (define (inc) 1467 | (set! x (+ x 1))) 1468 | (define (dec) 1469 | (set! x (- 1 x))) 1470 | (define (get) 1471 | x)) 1472 | ] 1473 | 1474 | The splicing variation is more convenient than the usual way: 1475 | 1476 | @#reader scribble/comment-reader 1477 | (i 1478 | (define-values (inc dec get) 1479 | (let ([x 0]) 1480 | (values (lambda () ;inc 1481 | (set! x (+ x 1))) 1482 | (lambda () ;dec 1483 | (set! x (- x 1))) 1484 | (lambda () ;get 1485 | x)))) 1486 | ) 1487 | 1488 | When there are many body forms---and we're generating them in a 1489 | macro---the splicing variations can be much easier. 1490 | 1491 | @; ---------------------------------------------------------------------------- 1492 | @; ---------------------------------------------------------------------------- 1493 | 1494 | @section{Robust macros: syntax-parse} 1495 | 1496 | Functions can be used in error. So can macros. 1497 | 1498 | @subsection{Error-handling strategies for functions} 1499 | 1500 | With plain old functions, we have several choices how to handle 1501 | misuse. 1502 | 1503 | 1. Don't check at all. 1504 | 1505 | @#reader scribble/comment-reader 1506 | (i 1507 | (define (misuse s) 1508 | (string-append s " snazzy suffix")) 1509 | ;; User of the function: 1510 | (misuse 0) 1511 | ;; I guess I goofed, but -- what is this "string-append" of which you 1512 | ;; speak?? 1513 | ) 1514 | 1515 | The problem is that the resulting error message will be confusing. Our 1516 | user thinks they're calling @racket[misuse], but they're getting an error 1517 | message from @racket[string-append]. In this simple example they 1518 | could probably guess what's happening, but in most cases they won't. 1519 | 1520 | 2. Write some error handling code. 1521 | 1522 | @#reader scribble/comment-reader 1523 | (i 1524 | (define (misuse s) 1525 | (unless (string? s) 1526 | (error 'misuse "expected a string, but got ~a" s)) 1527 | (string-append s " snazzy suffix")) 1528 | ;; User of the function: 1529 | (misuse 0) 1530 | ;; I goofed, and understand why! It's a shame the writer of the 1531 | ;; function had to work so hard to tell me. 1532 | ) 1533 | 1534 | Unfortunately the error code tends to overwhelm and/or obscure our 1535 | function definition. Also, the error message is good but not 1536 | great. Improving it would require even more error code. 1537 | 1538 | 3. Use a contract. 1539 | 1540 | @#reader scribble/comment-reader 1541 | (i 1542 | (define/contract (misuse s) 1543 | (string? . -> . string?) 1544 | (string-append s " snazzy suffix")) 1545 | ;; User of the function: 1546 | (misuse 0) 1547 | ;; I goofed, and understand why! I'm happier, and I hear the writer of 1548 | ;; the function is happier, too. 1549 | ) 1550 | 1551 | This is the best of both worlds. 1552 | 1553 | The contract is simple and concise. Even better, it's 1554 | declarative. We say what we want to happen, not how. 1555 | 1556 | On the other hand the user of our function gets a very detailed error 1557 | message. Plus, the message is in a standard, familiar format. 1558 | 1559 | 4. Use Typed Racket. 1560 | 1561 | @codeblock{#lang typed/racket} 1562 | @interaction[#:eval typed/evaluator 1563 | (: misuse (String -> String)) 1564 | (define (misuse s) 1565 | (string-append s " snazzy suffix")) 1566 | (misuse 0) 1567 | ] 1568 | 1569 | Even better, Typed Racket can catch usage mistakes up-front at compile 1570 | time. 1571 | 1572 | @subsection{Error-handling strategies for macros} 1573 | 1574 | For macros, we have similar choices. 1575 | 1576 | 1. Ignore the possibility of misuse. This choice is even worse for 1577 | macros. The default error messages are even less likely to make sense, 1578 | much less help our user know what to do. 1579 | 1580 | 2. Write error-handling code. We saw how much this complicated our 1581 | macros in our example of @secref["hash.refs"]. And while we're still 1582 | learning how to write macros, we especially don't want more cognitive 1583 | load and obfuscation. 1584 | 1585 | 3. Use @racket[syntax-parse]. For macros, this is the equivalent of 1586 | using contracts or types for functions. We can declare that input 1587 | pattern elements must be certain kinds of things, such as an 1588 | identifier. Instead of "types", the kinds are referred to as "syntax 1589 | classes". There are predefined syntax classes, plus we can define our 1590 | own. 1591 | 1592 | @subsection{Using @racket[syntax-parse]} 1593 | 1594 | November 1, 2012: So here's the deal. After writing everything up to 1595 | this point, I sat down to re-read the documentation for 1596 | @racket[syntax-parse]. It was...very understandable. I didn't feel 1597 | confused. 1598 | 1599 | Why? The documentation has a nice 1600 | @hyperlink["http://docs.racket-lang.org/syntax/stxparse-intro.html"]{Introduction} 1601 | with many simple examples, followed by an 1602 | @hyperlink["http://docs.racket-lang.org/syntax/stxparse-examples.html"]{Examples} 1603 | section illustrating many real-world scenarios. 1604 | 1605 | @italic{Update:} Furthermore, Ben Greenman has created a package whose 1606 | docs provide an excellent set of even more 1607 | @hyperlink["http://docs.racket-lang.org/syntax-parse-example/index.html"]{Syntax 1608 | Parse Examples}. 1609 | 1610 | Furthermore, everything I'd learned up to this point prepared me to 1611 | appreciate what @racket[syntax-parse] does, and why. The details of 1612 | how to use it seem pretty straightforward, so far. 1613 | 1614 | This might well be a temporary state of me "not knowing what I don't 1615 | know". As I dig in and use it more, maybe I'll discover something 1616 | confusing or tricky. If/when I do, I'll come back here and update 1617 | this. 1618 | 1619 | But for now I'll focus on improving the previous parts. 1620 | 1621 | @; ---------------------------------------------------------------------------- 1622 | @; ---------------------------------------------------------------------------- 1623 | 1624 | @section{References and Acknowledgments} 1625 | 1626 | Eli Barzilay's blog post, 1627 | @hyperlink["http://blog.racket-lang.org/2011/04/writing-syntax-case-macros.html" "Writing 1628 | ‘syntax-case’ Macros"], helped me understand many key details and 1629 | concepts, and inspired me to use a "bottom-up" approach. 1630 | 1631 | Eli wrote another blog post, 1632 | @hyperlink["http://blog.racket-lang.org/2008/02/dirty-looking-hygiene.html" "Dirty 1633 | Looking Hygiene"], which explains @racket[syntax-parameterize]. I 1634 | relied heavily on that, mostly just updating it since his post was 1635 | written before PLT Scheme was renamed to Racket. 1636 | 1637 | Matthew Flatt's 1638 | @hyperlink["http://www.cs.utah.edu/plt/publications/macromod.pdf" "Composable 1639 | and Compilable Macros: You Want it When? (PDF)"] explains how Racket 1640 | handles compile time vs. run time. 1641 | 1642 | @hyperlink["http://www.scheme.com/tspl4/syntax.html#./syntax:h0" "Chapter 1643 | 8"] of @italic{The Scheme Programming Language} by Kent Dybvig 1644 | explains @racket[syntax-rules] and @racket[syntax-case]. 1645 | 1646 | @hyperlink["http://www.ccs.neu.edu/racket/pubs/icfp10-cf.pdf" "Fortifying 1647 | Macros (PDF)"] is the paper by Ryan Culpepper and Matthias Felleisen 1648 | introducing @racket[syntax-parse]. 1649 | 1650 | Shriram Krishnamurthi looked at a very early draft and encouraged me 1651 | to keep going. Sam Tobin-Hochstadt and Robby Findler also encouraged 1652 | me. Matthew Flatt showed me how to make a Scribble 1653 | @racket[interaction] print @racket[syntax] as @racket["syntax"] rather 1654 | than as @racket["#'"]. Jay McCarthy helped me catch some mistakes and 1655 | confusions. Jon Rafkind provided suggestions. Kieron Hardy reported a 1656 | font issue and some typos. 1657 | 1658 | Finally, I noticed something strange. After writing much of this, when 1659 | I returned to some parts of the Racket documentation, I noticed it had 1660 | improved since I last read it. Of course, it was the same; I'd 1661 | changed. It's interesting how much of what we already know is 1662 | projected between the lines. My point is, the Racket documentation is 1663 | very good. The @italic{Guide} provides helpful examples and 1664 | tutorials. The @italic{Reference} is very clear and precise. 1665 | --------------------------------------------------------------------------------