Various edits.
This commit is contained in:
parent
b97caf7973
commit
7e53189a36
37
index.html
37
index.html
File diff suppressed because one or more lines are too long
64
main.rkt
64
main.rkt
|
@ -140,6 +140,11 @@ always outputs syntax for a string literal:
|
||||||
(define-syntax foo
|
(define-syntax foo
|
||||||
(lambda (stx)
|
(lambda (stx)
|
||||||
(syntax "I am foo")))
|
(syntax "I am foo")))
|
||||||
|
]
|
||||||
|
|
||||||
|
Using it:
|
||||||
|
|
||||||
|
@i[
|
||||||
(foo)
|
(foo)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -148,8 +153,8 @@ When we use @racket[define-syntax], we're making a transformer
|
||||||
encounter a chunk of syntax starting with @racket[foo], please give it
|
encounter a chunk of syntax starting with @racket[foo], please give it
|
||||||
to my transformer function, and replace it with the syntax I give back
|
to my transformer function, and replace it with the syntax I give back
|
||||||
to you." So Racket will give anything that looks like @racket[(foo
|
to you." So Racket will give anything that looks like @racket[(foo
|
||||||
...)] to our function, and we can change it. Much like a
|
...)] to our function, and we can return new syntax to use
|
||||||
search-and-replace.
|
instead. Much like a search-and-replace.
|
||||||
|
|
||||||
Maybe you know that the usual way to define a function in Racket:
|
Maybe you know that the usual way to define a function in Racket:
|
||||||
|
|
||||||
|
@ -201,7 +206,8 @@ 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 ignored the input syntax, and output a fixed
|
||||||
syntax. But usually we want to transform the input to something else.
|
syntax. But instead of throwing away the input, usually we want to
|
||||||
|
transform the input.
|
||||||
|
|
||||||
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}:
|
||||||
|
|
||||||
|
@ -226,18 +232,56 @@ as the source file, line number, and column. Finally, it has
|
||||||
information about lexical scoping (which you don't need to worry about
|
information about lexical scoping (which you don't need to worry about
|
||||||
now, but will turn out to be important later.)
|
now, but will turn out to be important later.)
|
||||||
|
|
||||||
There are a variety of functions available to access a syntax object:
|
There are a variety of functions available to access a syntax object.
|
||||||
|
Let's define a piece of syntax:
|
||||||
|
|
||||||
@i[
|
@i[
|
||||||
(define stx #'(if x (list "true") #f))
|
(define stx #'(if x (list "true") #f))
|
||||||
(syntax->datum stx)
|
stx
|
||||||
(syntax-e stx)
|
]
|
||||||
(syntax->list stx)
|
|
||||||
|
Now let's use functions that access the syntax object. The source
|
||||||
|
information functions:
|
||||||
|
|
||||||
|
@margin-note{@racket[(syntax-source stx)] is returning @racket['eval],
|
||||||
|
only becaue of how I'm generating this documentation, using an
|
||||||
|
evaluator to run code snippets in Scribble. Normally this would be
|
||||||
|
somthing like "my-file.rkt".}
|
||||||
|
|
||||||
|
@i[
|
||||||
(syntax-source stx)
|
(syntax-source stx)
|
||||||
(syntax-line stx)
|
(syntax-line stx)
|
||||||
(syntax-column stx)
|
(syntax-column stx)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
More interesting is the syntax "stuff" itself. @racket[syntax->datum]
|
||||||
|
converts it completely into an s-expression:
|
||||||
|
|
||||||
|
@i[
|
||||||
|
(syntax->datum stx)
|
||||||
|
]
|
||||||
|
|
||||||
|
Whereas @racket[syntax-e] only goes "one level down". It may return a
|
||||||
|
list that has syntax objects:
|
||||||
|
|
||||||
|
@i[
|
||||||
|
(syntax-e stx)
|
||||||
|
]
|
||||||
|
|
||||||
|
Each of those syntax objects could be converted by @racket[syntax-e],
|
||||||
|
and so on recursively---which is what @racket[syntax->datum] does.
|
||||||
|
|
||||||
|
In most cases, @racket[syntax->list] gives the same result as
|
||||||
|
@racket[syntax-e]:
|
||||||
|
|
||||||
|
@i[
|
||||||
|
(syntax->list stx)
|
||||||
|
]
|
||||||
|
|
||||||
|
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
|
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
|
||||||
pieces, and often introduce brand-new pieces.
|
pieces, and often introduce brand-new pieces.
|
||||||
|
@ -300,9 +344,9 @@ Normal Racket code runs at ... run time. Duh.
|
||||||
@margin-note{Instead of "compile time vs. run time", you may hear it
|
@margin-note{Instead of "compile time vs. run time", you may hear it
|
||||||
described as "syntax phase vs. runtime phase". Same difference.}
|
described as "syntax phase vs. runtime phase". Same difference.}
|
||||||
|
|
||||||
But a syntax transformer is run by the Racket compiler, as part of the
|
But a syntax transformer is called by Racket as part of the process of
|
||||||
process of parsing, expanding and understanding your code. In other
|
parsing, expanding, and compiling our program. In other words, our
|
||||||
words, your syntax transformer function is evaluated at compile time.
|
syntax transformer function is evaluated at compile time.
|
||||||
|
|
||||||
This aspect of macros lets you do things that simply aren't possible
|
This aspect of macros lets you do things that simply aren't possible
|
||||||
in normal code. One of the classic examples is something like the
|
in normal code. One of the classic examples is something like the
|
||||||
|
|
Loading…
Reference in New Issue
Block a user