Fear of Macros

Fear of Macros

1 Introduction
I learned Racket after 25 years of doing C/C++ imperative programming.
Some psychic whiplash resulted.
"All the parentheses" was actually not a big deal. Instead, the first +
1 Introduction
I learned Racket after 25 years of doing C/C++ imperative programming.
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 @@ -12,7 +12,9 @@ terminology soup. I marinaded myself in material, hoping it would eventually sink in after enough re-readings. I even found myself using trial and error, rather than having a clear mental model what was going on. Gah.
I’m starting to write this at the point where the shapes are slowly -emerging from the fog.
My primary motive is selfish. Explaining something forces me to learn +emerging from the fog.
If you have any corrections, criticisms, complaints, or whatever, +please +let me know.
My primary motive is selfish. Explaining something forces me to learn it more thoroughly. Plus I expect that if I write something with mistakes, other people will be eager to point them out and correct me. Is that a social-engineering variation of meta-programming? Next @@ -167,9 +169,9 @@ it, it didn’t work. It seems that foo-bar didn’t get defined.
prefer to work in Emacs (like I do), in a situation like this it’s worth firing up DrRacket temporarily to use the Macro Stepper.
It shows us:
(module anonymous-module racket (#%module-begin (define-syntax (hyphen-define/wrong1.1 stx) (syntax-case stx () [(_ a b (args ...) body0 body ...) (let ([name (string->symbol (format "~a-~a" #'a #'b))]) #'(define (name args ...) body0 body ...))])) (define (name) #t)))
It shows that we’re expanding to (define (name) #t), but we wanted to expand to (define (foo-bar) #t).
So the problem is we’re getting name when we wanted its -value, foo-bar.
> (define-syntax (hyphen-define/wrong1.2 stx) (syntax-case stx () [(_ a b (args ...) body0 body ...) (let ([name (string->symbol (format "~a-~a" #'a #'b))]) #'(define (name args ...) body0 body ...))])) > (hyphen-define/wrong1.2 foo bar () #t) > (foo-bar) foo-bar: undefined;
cannot reference an identifier before its definition
in module: 'program
The thing to reach for here is with-syntax. This will say -that name is in effect another pattern variable, and to use -its value:
> (define-syntax (hyphen-define/wrong1.3 stx) (syntax-case stx () [(_ a b (args ...) body0 body ...) (with-syntax ([name (datum->syntax stx (string->symbol (format "~a-~a" #'a #'b)))]) #'(define (name args ...) body0 body ...))])) > (hyphen-define/wrong1.3 foo bar () #t) > (foo-bar) foo-bar: undefined;
cannot reference an identifier before its definition
in module: 'program
Hmm. foo-bar still not defined. Back to the Macro Stepper. It says we’re expanding to:
(define (|#<syntax:11:24foo>-#<syntax:11:28 bar>|) #t).
Ah, that’s right. #'a and #'b are syntax +value, foo-bar.
The thing to reach for here is with-syntax. This will say +that name is in effect another pattern variable, the value of +which we want to use in our main output template.
> (define-syntax (hyphen-define/wrong1.3 stx) (syntax-case stx () [(_ a b (args ...) body0 body ...) (with-syntax ([name (datum->syntax stx (string->symbol (format "~a-~a" #'a #'b)))]) #'(define (name args ...) body0 body ...))])) > (hyphen-define/wrong1.3 foo bar () #t) > (foo-bar) foo-bar: undefined;
cannot reference an identifier before its definition
in module: 'program
Hmm. foo-bar still not defined. Back to the Macro Stepper. It says we’re expanding to:
(define (|#<syntax:11:24foo>-#<syntax:11:28 bar>|) #t).
Ah, that’s right. #'a and #'b are syntax objects. format is printing a representation of them as syntax objects. What we want is the datum inside the syntax object, the symbols foo and bar. So we should use diff --git a/main.rkt b/main.rkt index 88c8659..4757097 100644 --- a/main.rkt +++ b/main.rkt @@ -16,14 +16,14 @@ @image["fear-of-macros.jpg"] @title[#:version ""]{Fear of Macros} -@author{Greg Hendershott} +@author[@hyperlink["https://github.com/greghendershott/fear-of-macros/issues" + "Greg Hendershott"]] @smaller{Copyright (c) 2012 by Greg Hendershott. All rights reserved.} @para[@smaller["Last updated " (parameterize ([date-display-format 'iso-8601]) (date->string (current-date) #t))]] @table-of-contents{} - @; ---------------------------------------------------------------------------- @section{Introduction} @@ -50,6 +50,10 @@ going on. Gah. I'm starting to write this at the point where the shapes are slowly emerging from the fog. +@margin-note{If you have any corrections, criticisms, complaints, or whatever, +@hyperlink["https://github.com/greghendershott/fear-of-macros/issues" "please +let me know"].} + My primary motive is selfish. Explaining something forces me to learn it more thoroughly. Plus I expect that if I write something with mistakes, other people will be eager to point them out and correct