diff --git a/index.html b/index.html index a00d7f8..ea7a41c 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ Fear of Macros
1 Preface
2 The plan of attack
3 Transformers
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 Patterns and templates
4.1.1 "A pattern variable can’t be used outside of a template"
5 Syntax parameters
6 Robust macros: syntax-parse
7 Other questions
7.1 What’s the point of with-syntax?
7.2 What’s the point of begin-for-syntax?
7.3 What’s the point of racket/ splicing?
8 References and Acknowledgments
9 Epilogue

Fear of Macros

Copyright (c) 2012 by Greg Hendershott. All rights reserved. -
Last updated 2012-10-30 23:52:57

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 +

Last updated 2012-10-31 11:46:36

    1 Preface

    2 The plan of attack

    3 Transformers

      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 Patterns and templates

        4.1.1 "A pattern variable can’t be used outside of a template"

    5 Syntax parameters

    6 Robust macros: syntax-parse

    7 Other questions

      7.1 What’s the point of with-syntax?

      7.2 What’s the point of begin-for-syntax?

      7.3 What’s the point of racket/splicing?

    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 @@ -233,7 +233,16 @@ for tmp. The alias behavior is created by it isn’t otherwise defined, we get an error like we want:

> (displayln it)

it: can only be used inside aif

But we can still define it as a normal variable:

> (define it 10)
> it

10

6 Robust macros: syntax-parse

TO-DO. TO-DO. TO-DO.

7 Other questions

Hopefully I will answer these in the course of writing the other -sections. But just in case, here’s a running list:

7.1 What’s the point of with-syntax?

Done.

7.2 What’s the point of begin-for-syntax?

Done.

7.3 What’s the point of racket/splicing?

TO-DO.

8 References and Acknowledgments

Eli Barzliay’s blog post, +sections. But just in case, here’s a running list:

7.1 What’s the point of with-syntax?

Done.

7.2 What’s the point of begin-for-syntax?

Done.

7.3 What’s the point of racket/splicing?

I stared at racket/splicing for the longest time, not +understanding exactly how it works, or why I’d want to use it. As with +other aspects of Racket macros, step number one was to de-mythologize +it. This:

> (require racket/splicing)
> (splicing-let ([x 0])
    (define (get-x)
      x))
; get-x is visible out here:
> (get-x)

0

; but x is not:
> x

x: undefined;

 cannot reference an identifier before its definition

  in module: 'program

is shorthand for this:

> (define get-y
    (let ([y 0])
      (lambda ()
        y)))
; get-y is visible out here:
> (get-y)

0

; but y is not:
> y

y: undefined;

 cannot reference an identifier before its definition

  in module: 'program

This is the classic Lisp/Scheme/Racket idiom sometimes called "let +over lambda". A +koan +about closures and objects. A closure hides y, which can’t +be accessed directly, only via get-y.

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—and you are generating them in a +macro—the splicing variations can be much easier.

8 References and Acknowledgments

Eli Barzliay’s blog post, Writing ‘syntax-case’ Macros, helped me understand many key details and concepts. It also inspired me to use a "bottom-up" approach. However diff --git a/main.rkt b/main.rkt index f3b720a..8afc6a5 100644 --- a/main.rkt +++ b/main.rkt @@ -966,7 +966,73 @@ Done. @subsection{What's the point of @racket[racket/splicing]?} -TO-DO. +I stared at @racket[racket/splicing] for the longest time, not +understanding exactly how it works, or why I'd want to use it. As with +other aspects of Racket macros, step number one was to de-mythologize +it. This: + +@#reader scribble/comment-reader +(i +(require racket/splicing) +(splicing-let ([x 0]) + (define (get-x) + x)) +;; get-x is visible out here: +(get-x) +;; but x is not: +x +) + +is shorthand for this: + +@#reader scribble/comment-reader +(i +(define get-y + (let ([y 0]) + (lambda () + y))) +;; get-y is visible out here: +(get-y) +;; but y is not: +y +) + +This is the classic Lisp/Scheme/Racket idiom sometimes called "let +over lambda". @margin-note*{A +@hyperlink["http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html" "koan"] +about closures and objects.} A closure hides @racket[y], which can't +be accessed directly, only via @racket[get-y]. + +So why would we care about the splicing forms? They can be more +concise, especially when there are multiple body forms: + +@i[ +(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: + +@#reader scribble/comment-reader +(i +(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---and you are generating them in a +macro---the splicing variations can be much easier. @; ----------------------------------------------------------------------------