Merge branch 'master' into gh-pages

This commit is contained in:
Greg Hendershott 2012-10-26 14:34:51 -04:00
commit 0f2a73f6a7
3 changed files with 146 additions and 127 deletions

1
gh.css
View File

@ -7,7 +7,6 @@
.RktMod, .RktKw, .RktVar, .RktSym,
.RktRes, .RktOut, .RktCmt, .RktVal, .hspace {
font-family: monospace;
font-size: 95%;
white-space: inherit;
}

File diff suppressed because one or more lines are too long

139
main.rkt
View File

@ -26,9 +26,9 @@
@; ----------------------------------------------------------------------------
@section{Introduction}
@section{Preface}
I learned Racket after 25 years of doing C/C++ imperative programming.
I learned Racket after 25 years of mostly using C and C++.
Some psychic whiplash resulted.
@ -55,10 +55,10 @@ emerging from the fog.
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
question, please. :)
it more thoroughly. Plus 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 question,
please. :)
Finally I do hope it may help other people who have a similar
background and/or learning style as me.
@ -96,14 +96,14 @@ if we want to write the ever-popular anaphoric if, with a "magic
variable"? It turns out we've been protected from making certain kind
of mistakes. When we want to do this kind of thing on purpose, we use
a @racket[syntax parameter]. [There are other, older ways to do
this. We won't look at them. We also won't spend a lot of time talking
about "hygiene".]
this. We won't look at them. We also won't spend a lot of time
advocating "hygiene"---we'll just stipulate that it's good.]
4. Finally, we'll realize that our macros could be smarter when
they're used in error. Normal Racket functions can optionally have
contracts and types. These can catch mistakes and provide clear,
they're used in error. Normal Racket functions optionally can have
contracts and types. These catch usage mistakes and provide clear,
useful error messages. It would be great if there were something
similar for macros, and there is. One of the more-recent Racket macro
similar for macro. There is. One of the more-recent Racket macro
enhancements is @racket[syntax-parse].
@ -455,13 +455,13 @@ So let's try that:
@subsection{@racket[begin-for-syntax]}
We used @racket[(require (for-syntax racket/match))] to
@racket[require] @racket[match] because we needed to use
@racket[match] at compile time.
We used @racket[for-syntax] to @racket[require] the
@racket[racket/match] module because we needed to use @racket[match]
at compile time.
What if we wanted to define our own helper function to be used by a
macro? One way to do that is put it in another module, and
@racket[require] it using @racket[for/syntax], just like we did with
@racket[require] it using @racket[for-syntax], just like we did with
the @racket[racket/match] module.
If instead we want to put the helper in the same module, we can't
@ -483,13 +483,13 @@ To review:
@itemize[
@item{Syntax transformers work at compile time, not run time. The good
news is this means we can do things rearrange the pieces of syntax
without evaluating them. We can implement forms like @racket[if] that
simply couldn't work properly as run time functions.}
news is this means we can do things like rearrange the pieces of
syntax without evaluating them. We can implement forms like
@racket[if] that simply couldn't work properly as run time functions.}
@item{More good news is that there isn't some special, weird language
for writing syntax transformers. We can write these transformer
functions using the Racket language we already know.}
functions using the Racket language we already know and lovex.}
@item{The semi-bad news is that the familiarity can make it easy to forget
that we're not working at run time. Sometimes that's important to
@ -499,8 +499,7 @@ remember.
@item{For example only @racket[racket/base] is required for us
automatically. If we need other modules, we have to require them, and
do so @italic{for compile time} using
@racket[(require (for-syntax))].}
do so @italic{for compile time} using @racket[for-syntax].}
@item{Similarly, if we want to define helper functions in the same
file/module as the macros that use them, we need to wrap the
@ -552,10 +551,10 @@ Here's what it looks like using @racket[syntax-case]:
(our-if-using-syntax-case #t "true" "false")
]
Pretty similar, huh? The pattern part looks almost exactly the
same. The "template" part---where we specify the new syntax---is
simpler. We don't need to do quasi-quoting and unquoting. We don't need
to use @racket[datum->syntax]. We simply supply a template, which uses
Pretty similar, huh? The pattern matching part looks almost exactly
the same. The way we specify the new syntax is simpler. We don't need
to do quasi-quoting and unquoting. We don't need to use
@racket[datum->syntax]. Instead, we supply a "template", which uses
variables from the pattern.
There is a shorthand for simple pattern-matching cases, which expands
@ -613,17 +612,17 @@ A wrong first attempt is:
body0 body ...))]))
]
Huh. We have no idea what this error message means. Well, let's see.
The "template" is the @racket[#'(define (name args ...) body0 body
...)] portion. The @racket[let] isn't part of that template. It
sounds like we can't use @racket[a] (or @racket[b]) in the
@racket[let] part.
Huh. We have no idea what this error message means. Well, let's try to
work it out. The "template" the error message refers to is the
@racket[#'(define (name args ...) body0 body ...)] portion. The
@racket[let] isn't part of that template. It sounds like we can't use
@racket[a] (or @racket[b]) in the @racket[let] part.
Well, @racket[syntax-case] can have as many templates as you want. The
final expression is the obvious template, used to create the output
syntax. But you can use @racket[syntax] (a.k.a. #') on a pattern
variable. This makes another template, albeit a small, "fun size"
template. Let's try that:
In fact, @racket[syntax-case] can have as many templates as you
want. The obvious, required template is the final expression supplying
the output syntax. But you can use @racket[syntax] (a.k.a. #') on a
pattern variable. This makes another template, albeit a small, "fun
size" template. Let's try that:
@i[
(define-syntax (hyphen-define/wrong1.1 stx)
@ -641,8 +640,8 @@ But when we tried to use it, no luck. It seems that a function named
@racket[foo-bar] wasn't defined.
This is where the Macro Stepper in DrRacket is invaluable. Even if you
prefer to work in Emacs (like I do), this is a situation where it's
worth using DrRacket temporarily for its Macro Stepper.
prefer to work mostly in Emacs (like I do), this is a situation where
it's worth using DrRacket temporarily for its Macro Stepper.
@image[#:scale 0.5 "macro-stepper.png"]
@ -715,8 +714,8 @@ And now it works!
By the way, there is a utility function in @racket[racket/syntax]
called @racket[format-id] that lets us format identifier names more
succinctly. We remember to use @racket[for-syntax] with
@racket[require], since we need it at compile time:
succinctly. As we've learned, we need to @racket[require] the module
using @racket[for-syntax], since we need it at compile time:
@i[
(require (for-syntax racket/syntax))
@ -733,12 +732,24 @@ succinctly. We remember to use @racket[for-syntax] with
Using @racket[format-id] is convenient as it handles the tedium of
converting from syntax to datum and back again.
Recap: If you want to munge pattern variables for use in the template,
@racket[with-syntax] is your friend. Just remember you have to use
@racket[syntax] or @tt{#'} on the pattern variables to turn them into
fun size templates, and often also use @racket[syntax->datum] to get
the interesting value inside. Finally, @racket[format-id] is
convenient for formatting identifier names.
To review:
@itemize[
@item{If you want to munge pattern variables for use in the
template, @racket[with-syntax] is your friend.}
@item{You will need to use @racket[syntax] or @tt{#'} on the pattern
variables to turn them into "fun size" templates.}
@item{Usually you'll also need to use @racket[syntax->datum] to get
the interesting value inside.}
@item{@racket[format-id] is convenient for formatting identifier
names.}
]
@; ----------------------------------------------------------------------------
@ -818,12 +829,6 @@ parameters in Racket:
(current-foo)
]
@margin-note{Historically, there are other ways to do this. If you're
the target audience I'm writing for, you don't know them yet. I
suggest not bothering to learn them, yet. (Someday if you want to
understand someone else's older macros, you can learn about them
then.)}
That's a normal parameter. The syntax variation works similarly. The
idea is that we'll define @racket[it] to mean an error by
default. Only inside of our @racket[aif] will it have a meaningful
@ -888,23 +893,35 @@ TO-DO.
@; ----------------------------------------------------------------------------
@section{References/Acknowledgments}
@section{References and Acknowledgments}
Eli Barzliay wrote a blog post,
@hyperlink["http://blog.racket-lang.org/2011/04/writing-syntax-case-macros.html" "Writing
syntax-case Macros"], which explains many key details. However it's written
especially for people already familiar with "un-hygienic" "defmacro"
style macros. If you're not familiar with those, it may seem slightly
weird to the extent it's trying to convince you to change an opinion
you don't have. Even so, many key details are presented in Eli's typically
concise, clear fashion.
Eli Barzliay's blog post,
@hyperlink["http://blog.racket-lang.org/2011/04/writing-syntax-case-macros.html" "Writing
syntax-case Macros"], helped me understand many key details and
concepts. It also inspired me to use a "bottom-up" approach. However
he wrote for a specific audience. If you're not already familiar with
un-hygienic defmacro style macros, it may seem slightly weird to the
extent it's trying to convince you to change an opinion you don't
have. I'm writing for people who don't have any opinion about macros
at all, except maybe that macros seem scary and daunting.
Eli Barzilay wrote another blog post,
Eli wrote another blog post,
@hyperlink["http://blog.racket-lang.org/2008/02/dirty-looking-hygiene.html" "Dirty
Looking Hygiene"], which explains syntax-parameterize. I relied
heavily on that, mostly just updating it since his post was written
before PLT Scheme was renamed to Racket.
After initially wondering if I was asking the wrong question and
conflating two different issues :), Shriram Krishnamurthi looked at an
early draft and encouraged me to keep going. Sam Tobin-Hochstadt also
encouraged me.
After writing much of this, I noticed that Racket's documentation had
improved since I last read it. Actually it was the same, and very
good---I'd changed. It's interesting how much of what we already know
is projected between the lines. That's what makes it so hard to write
documentation. The only advantage I had was knowing so much less.
@; ----------------------------------------------------------------------------
@section{Epilogue}