Traditional Lisp macros work on S-expressions, but Racket and other
languages in the Scheme family rely on a richer representation of
programs. A syntax object is like an S-expression, but nodes
in a syntax object have source-location and binding information. This
extra information brings back a Plait-like requirement to coerce
between syntax objects and symbols, lists, numbers, etc.
What’s the value of 1?
| | |
| | That’s the number 1.
|
Can we type 1 in DrRacket’s interactions window and see the value?
| | |
| | Sure, assuming that the definitions window starts #lang racket.
|
What’s the value of #'1?
| | |
| | That’s a syntax object that has a 1 inside it. > #'1 | #<syntax:eval:3:0 1> |
|
| | I notice that the printed form of a syntax object seems to start with a source
location, and the line number gets bigger each time we enter a new expression. > #'1 | #<syntax:eval:4:0 1> | > #'1 | #<syntax:eval:5:0 1> |
|
Yes it does. Try syntax-quoting some things other than just 1.
| | |
| | > #'2 | #<syntax:eval:6:0 2> | > #'(+ 3 4) | #<syntax:eval:7:0 (+ 3 4)> | > #'my-function | #<syntax:eval:8:0 my-function> | | #<syntax:eval:9:0 (define (f x) (+ x 1))> | > #'#t | #<syntax:eval:10:0 #t> |
|
Is there a way to get the 1 out of #'1?
| | |
| | I could print #'1 and then try to parse the 1 back out.
That’s probably not the right way.
|
Try syntax-e.
| | |
| | So, if I want to inspect a big syntax tree, I could use syntax-e
plus list-manipulation functions to look at subtress.
|
You could, but syntax->list is often easier to use. If you want to recursively apply syntax-e, you can use
syntax->datum.
| | |
| | > (syntax->list #'(+ 3 4)) | '(#<syntax:eval:14:0 +> #<syntax:eval:14:0 3> #<syntax:eval:14:0 4>) | > (syntax->list #'(+ 3 (* 2 2))) | '(#<syntax:eval:15:0 +> #<syntax:eval:15:0 3> #<syntax:eval:15:0 (* 2 2)>) | > (syntax->datum #'(+ 3 (* 2 2))) | '(+ 3 (* 2 2)) | > (datum->syntax '(+ 3 4)) | datum->syntax: arity mismatch; | the expected number of arguments does not match the given | number | given: 1 | arguments...: | '(+ 3 4) |
Looks like my guess about datum->syntax was wrong.
|
A syntax object has more information than an S-expression, and
you have to supply the extra information. The first argument to
datum->syntax is an existing syntax object whose
binding information can be copied over, or you can use
#f to mean “no scopes.”
| | |
| | I don’t see the difference between those two.
|
The difference will matter later. For now, take my word for it
that #'here is usually a better choice than #f. What happens if the datum given to datum->syntax
already has syntax objects somewhere inside?
| | |
| | Maybe they’re left as-is. Yes, by pulling the syntax object from datum->syntax
back apart, I can see that the source locations for #'3
and #'4 where preserved by datum->syntax.
|
What’s the value of `(1 2 3)?
| | |
| | Using ` is the same as ', except that it
offers the possibility of escaping with ,. Since `(1 2 3) has no escape, it’s the same as '(1 2 3), which is a list of three numbers.
|
What’s the value of #`(1 2 3)?
| | |
| | I guess that #` is like ` in the same way
that #' is like ', so that’s a syntax object
that encapsulates a list of three syntax objects. > #`(1 2 3) | #<syntax:eval:22:0 (1 2 3)> |
And maybe it supports escapes as #,...
|
Did you need that datum->syntax?
| | |
| | > #`(1 2 #,(+ 3 4)) | #<syntax:eval:24:0 (1 2 7)> |
Apparently not! Why not?
|
The #` form inserts a datum->syntax for each
#, escape.
| | |
| | And if the escaped expression produces a syntax object, then
the automatic datum->syntax has no effect. But I can
see how the default conversion may be handy sometimes.
|
By the way, the #' form is a shorthand for
syntax, #` is a shorthand for
quasisyntax, #, is a shorthand for
unsyntax, and #,@ is a shorthand for
unsyntax-splicing.
| | |
| | > #`(1 2 #,@(list #'x #'y)) | #<syntax:eval:25:0 (1 2 x y)> |
|