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
|
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
|
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.
|
and terminology, and get very confused. I did.
|
||||||
|
|
||||||
1. Instead let's start with the basics: A syntax object and a function
|
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.
|
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
|
easier. We'll learn about @racket[syntax-case] and its shorthand
|
||||||
cousin, @racket[define-syntax-rule]. We'll discover we can get
|
cousin, @racket[define-syntax-rule]. We'll discover we can get
|
||||||
confused if we want to munge pattern variables before sticking them
|
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]{
|
@verbatim[#:indent 2]{
|
||||||
YOU ARE INSIDE A ROOM.
|
YOU ARE INSIDE A ROOM.
|
||||||
|
@ -227,9 +227,9 @@ which is used to evaluate and run our program.
|
||||||
|
|
||||||
@subsection{What's the input?}
|
@subsection{What's the input?}
|
||||||
|
|
||||||
Our examples so far ignored the input syntax, and output a fixed
|
Our examples so far have ignored the input syntax and output some
|
||||||
syntax. But instead of throwing away the input, usually we want to
|
fixed syntax. But typically we will want to transform in the input
|
||||||
transform the input.
|
syntax into somehing else.
|
||||||
|
|
||||||
Let's start by looking closely at what the input actually @italic{is}:
|
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.
|
object.
|
||||||
|
|
||||||
A syntax object consists of several things. The first part is the
|
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
|
Racket syntax is also decorated with some interesting information such
|
||||||
as the source file, line number, and column. Finally, it has
|
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
|
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],
|
@margin-note{@racket[(syntax-source stx)] is returning @racket['eval],
|
||||||
only becaue of how I'm generating this documentation, using an
|
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]
|
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[
|
@i[
|
||||||
(syntax->datum stx)
|
(syntax->datum stx)
|
||||||
|
@ -297,9 +297,8 @@ In most cases, @racket[syntax->list] gives the same result as
|
||||||
(syntax->list stx)
|
(syntax->list stx)
|
||||||
]
|
]
|
||||||
|
|
||||||
When would @racket[syntax-e] and @racket[syntax->list] differ? Let's
|
(When would @racket[syntax-e] and @racket[syntax->list] differ? Let's
|
||||||
not get side-tracked now.
|
not get side-tracked now.)
|
||||||
|
|
||||||
|
|
||||||
When we want to transform syntax, we'll generally take the pieces we
|
When we want to transform syntax, we'll generally take the pieces we
|
||||||
were given, maybe rearrange their order, perhaps change some of the
|
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}
|
@subsection{Compile time vs. run time}
|
||||||
|
|
||||||
@codeblock[#:indent 10]{
|
@codeblock0{
|
||||||
(define-syntax (foo stx)
|
(define-syntax (foo stx)
|
||||||
(make-pipe) ;This is not run time.
|
(make-pipe) ;Ce n'est pas le temps d'exécution
|
||||||
#'(void))
|
#'(void))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,6 +519,8 @@ So let's try that:
|
||||||
(our-if-using-match-v2 #t "true" "false")
|
(our-if-using-match-v2 #t "true" "false")
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Joy.
|
||||||
|
|
||||||
@; ----------------------------------------------------------------------------
|
@; ----------------------------------------------------------------------------
|
||||||
|
|
||||||
@subsection{@racket[begin-for-syntax]}
|
@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
|
@item{More good news is that there isn't some special, weird language
|
||||||
for writing syntax transformers. We can write these transformer
|
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
|
@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
|
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,
|
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]
|
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
|
Our template is using the symbol @racket[name] but we wanted its
|
||||||
value, such as @racket[foo-bar] in this use of our macro.
|
value, such as @racket[foo-bar] in this use of our macro.
|
||||||
|
|
||||||
Can we think of something we already know that behaves like
|
Is there anything we already know that behaves like this---where using
|
||||||
this---where using a variable in the template yields its value? Sure
|
a variable in the template yields its value? Yes: Pattern
|
||||||
we do: Pattern variables. Our pattern doesn't include @racket[name]
|
variables. Our pattern doesn't include @racket[name] because we don't
|
||||||
because we don't expect it in the original syntax---indeed the whole
|
expect it in the original syntax---indeed the whole point of this
|
||||||
point of this macro is to create it. So @racket[name] can't be in the
|
macro is to create it. So @racket[name] can't be in the main
|
||||||
main pattern. Fine---let's make an @italic{additional} pattern. We can
|
pattern. Fine---let's make an @italic{additional} pattern. We can do
|
||||||
do that using an additional, nested @racket[syntax-case]:
|
that using an additional, nested @racket[syntax-case]:
|
||||||
|
|
||||||
@i[
|
@i[
|
||||||
(define-syntax (hyphen-define/wrong1.2 stx)
|
(define-syntax (hyphen-define/wrong1.2 stx)
|
||||||
|
@ -829,7 +830,7 @@ And now it works!
|
||||||
|
|
||||||
Now for two shortcuts.
|
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]@margin-note*{Another name for
|
||||||
@racket[with-syntax] could be, "define pattern variable".}. This
|
@racket[with-syntax] could be, "define pattern variable".}. This
|
||||||
rearranges the @racket[syntax-case] to look more like a @racket[let]
|
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
|
@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
|
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
|
@item{If you want to munge pattern variables for use in the
|
||||||
template, @racket[with-syntax] is your friend, because it lets you
|
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
|
If you write programs for web services you deal with JSON, which is
|
||||||
represented in Racket by a @racket[jsexpr?]. JSON often has
|
represented in Racket by a @racket[jsexpr?]. JSON often has
|
||||||
dictionaries that contain other dictionaries. In a @racket[jsexpr?]
|
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{
|
@codeblock{
|
||||||
foo = js.a.b.c;
|
foo = js.a.b.c;
|
||||||
|
@ -1067,13 +1074,7 @@ foo = js.a.b.c;
|
||||||
|
|
||||||
In Racket it's not so convenient:
|
In Racket it's not so convenient:
|
||||||
|
|
||||||
@#reader scribble/comment-reader
|
@racketblock[(hash-ref (hash-ref (hash-ref js 'a) 'b) 'c)]
|
||||||
(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)
|
|
||||||
)
|
|
||||||
|
|
||||||
We can write a helper function to make this a bit cleaner:
|
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))
|
(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?
|
like JavaScript?
|
||||||
|
|
||||||
@#reader scribble/comment-reader
|
@#reader scribble/comment-reader
|
||||||
|
|
Loading…
Reference in New Issue
Block a user