From fb4c28b12d5b416e83ba1281a0bb7c574b29aeb6 Mon Sep 17 00:00:00 2001 From: Greg Hendershott Date: Mon, 12 Nov 2012 19:47:37 -0500 Subject: [PATCH 1/3] Fix a couple mistakes. --- main.rkt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.rkt b/main.rkt index a9bf5c3..d026e78 100644 --- a/main.rkt +++ b/main.rkt @@ -339,10 +339,10 @@ Using @racket[cdr] slices off the first item of the list, @racket[reverse] changes it to @racket[(values "i" "am" "backwards")]: @i[ -(reverse (cdr '("backwards" "am" "i" values))) +(reverse (cdr '(reverse-me "backwards" "am" "i" values))) ] -Finally we use @racket[syntax->datum] to convert this back to +Finally we use @racket[datum->syntax] to convert this back to @racket[syntax]: @i[ From 96c20cbade4e6958d63052200561018efaeb0c39 Mon Sep 17 00:00:00 2001 From: Greg Hendershott Date: Mon, 12 Nov 2012 19:47:58 -0500 Subject: [PATCH 2/3] Update acknowledgments --- main.rkt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.rkt b/main.rkt index d026e78..927ae48 100644 --- a/main.rkt +++ b/main.rkt @@ -1547,7 +1547,8 @@ 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["#'"]. Jay McCarthy helped me -catch some mistakes and confusions. +catch some mistakes and confusions. Jon Rafkind pointed out some +problems. Kieron Hardy reported a font issue and some typos. Finally, I noticed something strange. After writing much of this, when I returned to some parts of the Racket documentation, I noticed it had From 7daf8fda80e1b47a217ea7c7c82fccceea7d6222 Mon Sep 17 00:00:00 2001 From: Greg Hendershott Date: Mon, 12 Nov 2012 19:48:25 -0500 Subject: [PATCH 3/3] Regen html --- index.html | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 7fa77ba..2726a3f 100644 --- a/index.html +++ b/index.html @@ -1,6 +1,6 @@ -Fear of Macros

Fear of Macros

-
Copyright (c) 2012 by Greg Hendershott. All rights reserved.
Last updated 2012-11-08 16:16:21
Feedback and corrections are welcome here.

Contents:

    1 Preface

    2 Our plan of attack

    3 Transform!

      3.1 What is a syntax transformer?

      3.2 What’s the input?

      3.3 Actually transforming the input

      3.4 Compile time vs. run time

      3.5 begin-for-syntax

    4 Pattern matching: syntax-case and syntax-rules

      4.1 Pattern variable vs. template—fight!

        4.1.1 with-syntax

        4.1.2 format-id

      4.2 Making our own struct

      4.3 Using dot notation for nested hash lookups

    5 Syntax parameters

    6 What’s the point of splicing-let?

    7 Robust macros: syntax-parse

      7.1 Error-handling strategies for functions

      7.2 Error-handling strategies for macros

      7.3 Using syntax/parse

    8 References and Acknowledgments

    9 Epilogue

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 +Fear of Macros

Fear of Macros

+
Copyright (c) 2012 by Greg Hendershott. All rights reserved.
Last updated 2012-11-12 19:48:10
Feedback and corrections are welcome here.

Contents:

    1 Preface

    2 Our plan of attack

    3 Transform!

      3.1 What is a syntax transformer?

      3.2 What’s the input?

      3.3 Actually transforming the input

      3.4 Compile time vs. run time

      3.5 begin-for-syntax

    4 Pattern matching: syntax-case and syntax-rules

      4.1 Pattern variable vs. template—fight!

        4.1.1 with-syntax

        4.1.2 format-id

        4.1.3 Another example

      4.2 Making our own struct

      4.3 Using dot notation for nested hash lookups

    5 Syntax parameters

    6 What’s the point of splicing-let?

    7 Robust macros: syntax-parse

      7.1 Error-handling strategies for functions

      7.2 Error-handling strategies for macros

      7.3 Using syntax/parse

    8 References and Acknowledgments

    9 Epilogue

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 @@ -84,7 +84,7 @@ given:

> (syntax->datum #'(reverse-me "backwards" "am" "i" values))

'(reverse-me "backwards" "am" "i" values)

Using cdr slices off the first item of the list, reverse-me, leaving the remainder: ("backwards" "am" "i" values). Passing that to -reverse changes it to (values "i" "am" "backwards"):

> (reverse (cdr '("backwards" "am" "i" values)))

'(values "i" "am")

Finally we use syntax->datum to convert this back to +reverse changes it to (values "i" "am" "backwards"):

> (reverse (cdr '(reverse-me "backwards" "am" "i" values)))

'(values "i" "am" "backwards")

Finally we use datum->syntax to convert this back to syntax:

> (datum->syntax #f '(values "i" "am" "backwards"))

#<syntax (values "i" "am" "backwards")>

That’s what our transformer function gives back to the Racket compiler, and that syntax is evaluated:

> (values "i" "am" "backwards")

"i"

"am"

"backwards"

3.4 Compile time vs. run time

(define-syntax (foo stx)
  (make-pipe) ;Ce n'est pas le temps d'exécution
  #'(void))

Normal Racket code runs at ... run time. Duh.

Instead of "compile time vs. run time", you may hear it described as "syntax phase vs. runtime phase". Same difference.

But a syntax transformer is called by Racket as part of the process of @@ -223,8 +223,8 @@ mysterious.

4.1.2 require the module using for-syntax, since we need it at compile time:

> (require (for-syntax racket/syntax))
> (define-syntax (hyphen-define/ok3 stx)
    (syntax-case stx ()
      [(_ a b (args ...) body0 body ...)
       (with-syntax ([name (format-id stx "~a-~a" #'a #'b)])
         #'(define (name args ...)
             body0 body ...))]))
> (hyphen-define/ok3 bar baz () #t)
> (bar-baz)

#t

Using format-id is convenient as it handles the tedium of converting from syntax to symbol datum to string ... and all the way -back.

Finally, here’s a variation that accepts any number of name parts that -are joined with hyphens:

> (require (for-syntax racket/string racket/syntax))
> (define-syntax (hyphen-define* stx)
    (syntax-case stx ()
      [(_ (names ...) (args ...) body0 body ...)
       (let* ([names/sym (map syntax-e (syntax->list #'(names ...)))]
              [names/str (map symbol->string names/sym)]
              [name/str (string-join names/str "-")]
              [name/sym (string->symbol name/str)])
         (with-syntax ([name (datum->syntax stx name/sym)])
           #`(define (name args ...)
               body0 body ...)))]))
> (hyphen-define* (foo bar baz) (v) (* 2 v))
> (foo-bar-baz 50)

100

To review:

  • You can’t use a pattern variable outside of a template. But +back.

    4.1.3 Another example

    Finally, here’s a variation that accepts an arbitary number of name +parts to be joined with hyphens:

    > (require (for-syntax racket/string racket/syntax))
    > (define-syntax (hyphen-define* stx)
        (syntax-case stx ()
          [(_ (names ...) (args ...) body0 body ...)
           (let* ([names/sym (map syntax-e (syntax->list #'(names ...)))]
                  [names/str (map symbol->string names/sym)]
                  [name/str (string-join names/str "-")]
                  [name/sym (string->symbol name/str)])
             (with-syntax ([name (datum->syntax stx name/sym)])
               #`(define (name args ...)
                   body0 body ...)))]))
    > (hyphen-define* (foo bar baz) (v) (* 2 v))
    > (foo-bar-baz 50)

    100

    To review:

    • You can’t use a pattern variable outside of a template. But you can use syntax or # on a pattern variable to make an ad hoc, "fun size" template.

    • If you want to munge pattern variables for use in the template, with-syntax is your friend, because it lets you @@ -343,7 +343,8 @@ 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 "#'". Jay McCarthy helped me -catch some mistakes and confusions.

      Finally, I noticed something strange. After writing much of this, when +catch some mistakes and confusions. Jon Rafkind pointed out some +problems. Kieron Hardy reported a font issue and some typos.

      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