Various small edits.
This commit is contained in:
parent
ab6ca8cd39
commit
e918444b48
73
main.rkt
73
main.rkt
|
@ -79,7 +79,7 @@ understand the answers and solutions.
|
|||
|
||||
@; ----------------------------------------------------------------------------
|
||||
|
||||
@section{The plan of attack}
|
||||
@section{Our plan of attack}
|
||||
|
||||
The macro system you will mostly want to use for production-quality
|
||||
macros is called @racket[syntax-parse]. And don't worry, we'll get to
|
||||
|
@ -89,10 +89,10 @@ But if we start there, you're likely to feel overwhelmed by concepts
|
|||
and terminology, and get very confused. I did.
|
||||
|
||||
1. Instead let's start with the basics: A syntax object and a function
|
||||
to change it (a "transformer"). We'll work at that level for awhile to
|
||||
to change it---a "transformer". We'll work at that level for awhile to
|
||||
get comfortable and to de-mythologize this whole macro business.
|
||||
|
||||
2. Next, we'll realize that some pattern-matching would make life
|
||||
2. Soon we'll realize that pattern-matching would make life
|
||||
easier. We'll learn about @racket[syntax-case] and its shorthand
|
||||
cousin, @racket[define-syntax-rule]. We'll discover we can get
|
||||
confused if we want to munge pattern variables before sticking them
|
||||
|
@ -117,7 +117,7 @@ enhancements is @racket[syntax-parse].
|
|||
@; ----------------------------------------------------------------------------
|
||||
@; ----------------------------------------------------------------------------
|
||||
|
||||
@section{Transformers}
|
||||
@section{Transform!}
|
||||
|
||||
@verbatim[#:indent 2]{
|
||||
YOU ARE INSIDE A ROOM.
|
||||
|
@ -227,9 +227,9 @@ which is used to evaluate and run our program.
|
|||
|
||||
@subsection{What's the input?}
|
||||
|
||||
Our examples so far ignored the input syntax, and output a fixed
|
||||
syntax. But instead of throwing away the input, usually we want to
|
||||
transform the input.
|
||||
Our examples so far have ignored the input syntax and output some
|
||||
fixed syntax. But typically we will want to transform in the input
|
||||
syntax into somehing else.
|
||||
|
||||
Let's start by looking closely at what the input actually @italic{is}:
|
||||
|
||||
|
@ -244,7 +244,7 @@ The @racket[(print stx)] shows what our transformer is given: a syntax
|
|||
object.
|
||||
|
||||
A syntax object consists of several things. The first part is the
|
||||
s-expression representing the code, such as @racket['(+ 1 2)].
|
||||
S-expression representing the code, such as @racket['(+ 1 2)].
|
||||
|
||||
Racket syntax is also decorated with some interesting information such
|
||||
as the source file, line number, and column. Finally, it has
|
||||
|
@ -260,7 +260,7 @@ stx
|
|||
]
|
||||
|
||||
Now let's use functions that access the syntax object. The source
|
||||
information functions:
|
||||
information functions are:
|
||||
|
||||
@margin-note{@racket[(syntax-source stx)] is returning @racket['eval],
|
||||
only becaue of how I'm generating this documentation, using an
|
||||
|
@ -274,7 +274,7 @@ somthing like "my-file.rkt".}
|
|||
]
|
||||
|
||||
More interesting is the syntax "stuff" itself. @racket[syntax->datum]
|
||||
converts it completely into an s-expression:
|
||||
converts it completely into an S-expression:
|
||||
|
||||
@i[
|
||||
(syntax->datum stx)
|
||||
|
@ -297,9 +297,8 @@ In most cases, @racket[syntax->list] gives the same result as
|
|||
(syntax->list stx)
|
||||
]
|
||||
|
||||
When would @racket[syntax-e] and @racket[syntax->list] differ? Let's
|
||||
not get side-tracked now.
|
||||
|
||||
(When would @racket[syntax-e] and @racket[syntax->list] differ? Let's
|
||||
not get side-tracked now.)
|
||||
|
||||
When we want to transform syntax, we'll generally take the pieces we
|
||||
were given, maybe rearrange their order, perhaps change some of the
|
||||
|
@ -356,9 +355,9 @@ compiler, and @italic{that} syntax is evaluated:
|
|||
|
||||
@subsection{Compile time vs. run time}
|
||||
|
||||
@codeblock[#:indent 10]{
|
||||
@codeblock0{
|
||||
(define-syntax (foo stx)
|
||||
(make-pipe) ;This is not run time.
|
||||
(make-pipe) ;Ce n'est pas le temps d'exécution
|
||||
#'(void))
|
||||
}
|
||||
|
||||
|
@ -520,6 +519,8 @@ So let's try that:
|
|||
(our-if-using-match-v2 #t "true" "false")
|
||||
]
|
||||
|
||||
Joy.
|
||||
|
||||
@; ----------------------------------------------------------------------------
|
||||
|
||||
@subsection{@racket[begin-for-syntax]}
|
||||
|
@ -569,7 +570,7 @@ syntax without evaluating them. We can implement forms like
|
|||
|
||||
@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 and lovex.}
|
||||
functions using the Racket language we already know and love.}
|
||||
|
||||
@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
|
||||
|
@ -671,7 +672,7 @@ working.
|
|||
|
||||
@; ----------------------------------------------------------------------------
|
||||
|
||||
@subsection{"A pattern variable can't be used outside of a template"}
|
||||
@subsection{Pattern variable vs. template---fight!}
|
||||
|
||||
Let's say we want to define a function with a hyphenated name, a-b,
|
||||
but we supply the a and b parts separately. The Racket @racket[struct]
|
||||
|
@ -754,13 +755,13 @@ Well that explains it. Instead, we wanted to expand to:
|
|||
Our template is using the symbol @racket[name] but we wanted its
|
||||
value, such as @racket[foo-bar] in this use of our macro.
|
||||
|
||||
Can we think of something we already know that behaves like
|
||||
this---where using a variable in the template yields its value? Sure
|
||||
we do: Pattern variables. Our pattern doesn't include @racket[name]
|
||||
because we don't expect it in the original syntax---indeed the whole
|
||||
point of this macro is to create it. So @racket[name] can't be in the
|
||||
main pattern. Fine---let's make an @italic{additional} pattern. We can
|
||||
do that using an additional, nested @racket[syntax-case]:
|
||||
Is there anything we already know that behaves like this---where using
|
||||
a variable in the template yields its value? Yes: Pattern
|
||||
variables. Our pattern doesn't include @racket[name] because we don't
|
||||
expect it in the original syntax---indeed the whole point of this
|
||||
macro is to create it. So @racket[name] can't be in the main
|
||||
pattern. Fine---let's make an @italic{additional} pattern. We can do
|
||||
that using an additional, nested @racket[syntax-case]:
|
||||
|
||||
@i[
|
||||
(define-syntax (hyphen-define/wrong1.2 stx)
|
||||
|
@ -829,7 +830,7 @@ And now it works!
|
|||
|
||||
Now for two shortcuts.
|
||||
|
||||
Instead of an additional, nested @racket[syntax-case] we could use
|
||||
Instead of an additional, nested @racket[syntax-case], we could use
|
||||
@racket[with-syntax]@margin-note*{Another name for
|
||||
@racket[with-syntax] could be, "define pattern variable".}. This
|
||||
rearranges the @racket[syntax-case] to look more like a @racket[let]
|
||||
|
@ -901,7 +902,7 @@ To review:
|
|||
|
||||
@item{You can't use a pattern variable outside of a template. But
|
||||
you can use @racket[syntax] or @tt{#'} on a pattern variable to make
|
||||
an ad hoc "fun size" template.}
|
||||
an ad hoc, "fun size" template.}
|
||||
|
||||
@item{If you want to munge pattern variables for use in the
|
||||
template, @racket[with-syntax] is your friend, because it lets you
|
||||
|
@ -1057,9 +1058,15 @@ pieces.
|
|||
If you write programs for web services you deal with JSON, which is
|
||||
represented in Racket by a @racket[jsexpr?]. JSON often has
|
||||
dictionaries that contain other dictionaries. In a @racket[jsexpr?]
|
||||
these are represented by nested @racket[hasheq] tables.
|
||||
these are represented by nested @racket[hasheq] tables:
|
||||
|
||||
JavaScript you can use dot notation:
|
||||
@#reader scribble/comment-reader
|
||||
(i
|
||||
; Nested `hasheq's typical of a jsexpr:
|
||||
(define js (hasheq 'a (hasheq 'b (hasheq 'c "value"))))
|
||||
)
|
||||
|
||||
In JavaScript you can use dot notation:
|
||||
|
||||
@codeblock{
|
||||
foo = js.a.b.c;
|
||||
|
@ -1067,13 +1074,7 @@ foo = js.a.b.c;
|
|||
|
||||
In Racket it's not so convenient:
|
||||
|
||||
@#reader scribble/comment-reader
|
||||
(i
|
||||
; Nested hasheqs typical of a jsexpr:
|
||||
(define js (hasheq 'a (hasheq 'b (hasheq 'c "value"))))
|
||||
; Typical annoying code to get something:
|
||||
(hash-ref (hash-ref (hash-ref js 'a) 'b) 'c)
|
||||
)
|
||||
@racketblock[(hash-ref (hash-ref (hash-ref js 'a) 'b) 'c)]
|
||||
|
||||
We can write a helper function to make this a bit cleaner:
|
||||
|
||||
|
@ -1092,7 +1093,7 @@ We can write a helper function to make this a bit cleaner:
|
|||
(hash-refs js '(a b c))
|
||||
)
|
||||
|
||||
That's not bad. Can we go even further and use a dot notation somewhat
|
||||
That's better. Can we go even further and use a dot notation somewhat
|
||||
like JavaScript?
|
||||
|
||||
@#reader scribble/comment-reader
|
||||
|
|
Loading…
Reference in New Issue
Block a user