Fear of Macros

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 +
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—
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. @; ----------------------------------------------------------------------------