Fear of Macros

Contents:
1 Preface
I learned Racket after 25 years of mostly using C and C++.
Some psychic whiplash resulted.
"All the parentheses" was actually not a big deal. Instead, the first +
Contents:
1 Preface
I learned Racket after 25 years of mostly using C and C++.
Some psychic whiplash resulted.
"All the parentheses" was actually not a big deal. Instead, the first mind warp was functional programming. Before long I wrapped my brain around it, and went on to become comfortable and effective with many other aspects and features of Racket.
But two final frontiers remained: Macros and continuations.
I found that simple macros were easy and understandable, plus there @@ -288,7 +288,8 @@ over lambda". get-y. , which can only be accessed via
So why would we care about the splicing forms? They can be more concise, especially when there are multiple body forms:
> (require racket/splicing)
> (splicing-let ([x 0]) (define (inc) (set! x (+ x 1))) (define (dec) (set! x (- x 1))) (define (get) x))
The splicing variation is more convenient than the usual way:
> (define-values (inc dec get) (let ([x 0]) (values (lambda () ; inc (set! x (+ 1 x))) (lambda () ; dec (set! x (- 1 x))) (lambda () ; get x))))
When there are many body forms—
7 Robust macros: syntax-parse
Functions can be used in error. So can macros.
7.1 Error-handling strategies for functions
With plain old functions, we have several choices.
1. Don’t check at all.
> (define (misuse s) (string-append s " snazzy suffix")) ; User of the function: > (misuse 0) string-append: contract violation
expected: string?
given: 0
argument position: 1st
other arguments...:
" snazzy suffix"
; I guess I goofed, but – what is this "string-append" of which you ; speak??
The problem is that the resulting error message will be confusing. Our
+macro—
7 Robust macros: syntax-parse
Functions can be used in error. So can macros.
7.1 Error-handling strategies for functions
With plain old functions, we have several choices how to handle +misuse.
1. Don’t check at all.
> (define (misuse s) (string-append s " snazzy suffix")) ; User of the function: > (misuse 0) string-append: contract violation
expected: string?
given: 0
argument position: 1st
other arguments...:
" snazzy suffix"
; I guess I goofed, but – what is this "string-append" of which you ; speak??
The problem is that the resulting error message will be confusing. Our user thinks they’re calling misuse, but is getting an error message from string-append. In this simple example they could probably guess what’s happening, but in most cases they won’t.
2. Write some error handling code.
> (define (misuse s) (unless (string? s) (error 'misuse "expected a string, but got ~a" s)) (string-append s " snazzy suffix")) ; User of the function: > (misuse 0) misuse: expected a string, but got 0
; I goofed, and understand why! It's a shame the writer of the ; function had to work so hard to tell me.
Unfortunately the error code tends to overwhelm and/or obscure our @@ -305,8 +306,9 @@ learning how to write macros, we especially don’t want more cognitive load and obfuscation.
3. Use syntax/parse. For macros, this is the equivalent of using contracts or types for functions. We can declare that input pattern elements must be certain kinds of things, such as an -identifier. Instead of "types", the things are referred to as "syntax -classes". There are predefined syntax classes, plus we can define our own.
7.3 Using syntax/parse
November 1, 2012: So here’s the deal. After writing everything up to +identifier. Instead of "types", the kinds are referred to as "syntax +classes". There are predefined syntax classes, plus we can define our +own.
7.3 Using syntax/parse
November 1, 2012: So here’s the deal. After writing everything up to this point, I sat down to re-read the documentation for syntax/parse. It was...very understandable. I didn’t feel confused.
<span style='accent: "Kenau-Reeves"'> Whoa. </span>
Why? The documentation is written very well. Also, everything up to @@ -339,7 +341,8 @@ conflating two different issues :), Shriram Krishnamurthi looked at an early draft and encouraged me to keep going. Sam Tobin-Hochstadt and Robby Findler also encouraged me. Matthew Flatt showed me how to make a Scribble interaction print syntax as -"syntax" rather than as "#'".
Finally, I noticed something strange. After writing much of this, when +"syntax" rather than as "#'". Jay McCarthy helped me +catch some mistakes and confusions.
Finally, I noticed something strange. After writing much of this, when I returned to some parts of the Racket documentation, I noticed it had improved since I last read it. Of course, it was the same. I’d changed. It’s interesting how much of what we already know is diff --git a/main.rkt b/main.rkt index 6951a8c..f940316 100644 --- a/main.rkt +++ b/main.rkt @@ -1385,7 +1385,8 @@ Functions can be used in error. So can macros. @subsection{Error-handling strategies for functions} -With plain old functions, we have several choices. +With plain old functions, we have several choices how to handle +misuse. 1. Don't check at all. @@ -1451,10 +1452,7 @@ message. Plus, the message is in a standard, familiar format. (: misuse (String -> String)) (define (misuse s) (string-append s " snazzy suffix")) -;; User of the function: (misuse 0) -;; I goofed, and understand why! I hear the writer of the function is -;; a cheerful type. ] With respect to error handling, Typed Racket has the same benefits as @@ -1476,8 +1474,9 @@ load and obfuscation. 3. Use @racket[syntax/parse]. For macros, this is the equivalent of using contracts or types for functions. We can declare that input pattern elements must be certain kinds of things, such as an -identifier. Instead of "types", the things are referred to as "syntax -classes". There are predefined syntax classes, plus we can define our own. +identifier. Instead of "types", the kinds are referred to as "syntax +classes". There are predefined syntax classes, plus we can define our +own. @subsection{Using @racket[syntax/parse]} @@ -1541,7 +1540,8 @@ conflating two different issues :), Shriram Krishnamurthi looked at an early draft and encouraged me to keep going. Sam Tobin-Hochstadt and Robby Findler also encouraged me. Matthew Flatt showed me how to make a Scribble @racket[interaction] print @racket[syntax] as -@racket["syntax"] rather than as @racket["#'"]. +@racket["syntax"] rather than as @racket["#'"]. Jay McCarthy helped me +catch some mistakes and confusions. Finally, I noticed something strange. After writing much of this, when I returned to some parts of the Racket documentation, I noticed it had