On this page:
4.1 The Little Syntaxer
4.2 Datum to Syntax
7.4.0.4

4 Syntax Objects

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.

4.1 The Little Syntaxer

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.

> 1

1

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>

> #'(define (f x)
      (+ x 1))

#<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.

 

 

> (syntax-e #'1)

1

> (syntax-e #'2)

2

> (syntax-e #'(+ 3 4))

'(#<syntax:eval:13:0 +> #<syntax:eval:13:0 3> #<syntax:eval:13:0 4>)

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.”

 

 

> (datum->syntax #f '(+ 3 4))

#<syntax (+ 3 4)>

> (datum->syntax #'here '(+ 3 4))

#<syntax (+ 3 4)>

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.

> (datum->syntax #'here (list '+ #'3 #'4))

#<syntax (+ 3 4)>

> (syntax->list (datum->syntax #'here (list '+ #'3 #'4)))

'(#<syntax +> #<syntax:eval:21:0 3> #<syntax:eval:21:0 4>)

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 #,...

> #`(1 2 #,(datum->syntax #'here (+ 3 4)))

#<syntax:eval:23:0 (1 2 7)>

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)>

4.2 Datum to Syntax

The datum->syntax function takes up to four arguments: