# Some basic questions about macros and scope

**URL:** <https://racket.discourse.group/t/some-basic-questions-about-macros-and-scope/2731>\
**Category:** Questions & Answers\
**Tags:** macro\
**Created:** [February 21, 2024, 10:32am UTC](https://racket.discourse.group/t/some-basic-questions-about-macros-and-scope/2731 "2024-02-21T10:32:48Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![neteroster](https://avatars.discourse-cdn.com/v4/letter/n/eada6e/32.png) [@neteroster](https://racket.discourse.group/u/neteroster)\
**Post date:** [February 21, 2024, 10:32am UTC](https://racket.discourse.group/t/some-basic-questions-about-macros-and-scope/2731/1 "2024-02-21T10:32:48Z")

</div>

Recently, I have been reading [Fear of Macros](https://www.greghendershott.com/fear-of-macros/pattern-matching.html) to understand some basic usage of macros in Racket. I found everything relatively easy to understand until I encountered the content related to lexical context.

If my understanding is correct, a syntax object contains at least a piece of literal program and the binding information of the symbols within it. For example, if I write

```scheme
(define x 1)
(define s #'(list x y))
(define y 2)

```

In DrRacket, there will be an arrow from the first x to the x in the syntax object, and the same for y. That is to say, `#'...` captures the binding environment at its location and then embeds it into the syntax object it represents.

However, I am confused about the use of `#'` within a macro (i.e., `define-syntax` block). In Fear of Macros, the author first performs syntax transformation through `datum->syntax`, explicitly providing the lexical context `stx`:

```scheme
; Fear of Macros, beginning of Chapter 4
(require (for-syntax racket/match))
(define-syntax (our-if-using-match-v2 stx)
  (match (syntax->list stx)
    [(list _ condition true-expr false-expr)
     (datum->syntax stx `(cond [,condition ,true-expr]
                               [else ,false-expr]))]))

```

After introducing `syntax-case`, the above code segment is written as

```scheme
; Below the above code segment
(define-syntax (our-if-using-syntax-case stx)
    (syntax-case stx ()
      [(_ condition true-expr false-expr)
       #'(cond [condition true-expr]
               [else false-expr])]))

```

What environment does `#'` capture here? Is it `stx`, or something else?

Another point that confuses me is about a description of `format-id` (4.1.3). For the program

```scheme
; Fear of Macros: 4.1.3
> (require (for-syntax racket/syntax))
> (define-syntax (hyphen-define/ok3 stx)
    (syntax-case stx ()
      [(_ a b (args ...) body0 body ...)
       (with-syntax ([name (format-id #'a "~a-~a" #'a #'b)])
         #'(define (name args ...)
             body0 body ...))]))
> (hyphen-define/ok3 bar baz () #t)
> (bar-baz)

```

The author mentions

> The first argument of format-id, lctx, is the lexical context of the identifier that will be created. You almost never want to supply stx—the overall chunk of syntax that the macro transforms. Instead, you want to supply some more specific bit of syntax, such as an identifier that the user has provided to the macro. In this example, we’re using #'a. The resulting identifier will have the same scope as that which the user provided. This is more likely to behave as the user expects, especially when our macro is composed with other macros.

I don't quite understand this part. For example, in the code segment above, i.e., `(hyphen-define/ok3 bar baz () #t)`, the binding environment of `bar` and `(hyphen-define/ok3 bar baz () #t)` seems to be the same. Is my understanding incorrect, or is it indeed possible to construct a situation where the binding environments of the two are different?

* * *

These are my two main questions. As a Racket beginner, I hope to understand some language concepts as accurately as possible to avoid greater misunderstandings. So, if you notice any potential deviations in my understanding of any concepts from my description, I hope you can point them out directly.

Thank you very much for reading and in advance for your answers!

(Sorry for my poor English, this question is mostly translated by GPT.)

* * *

## Append

I'm trying another program:

```scheme
(define x 1)
(define s #'(list x y))
(define y 2)
;;;
(define s2
  (let ([z 3])
    #'z))

```

This time, the `z` in the syntax object isn't bound. I'm confused with this. What's the difference between `z` and `x, y`? I know that if I change `let` to `with-syntax`, z will be bound, but why?

* * *

## Append 2

I further read [The Racket Reference - Syntax Model](https://docs.racket-lang.org/reference/syntax-model.html#%28tech._syntax._object%29), and I think my previous understanding of `#'` or `(syntax ...)` was incorrect. In fact, `(syntax ...)` does not capture any **non-global** environment **outside**. The `x` and `y` in `s` are bound merely because `x` and `y` are top-level variables. Is this correct?

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [February 21, 2024, 3:23pm UTC](https://racket.discourse.group/t/some-basic-questions-about-macros-and-scope/2731/2 "2024-02-21T15:23:34Z")

</div>

> If my understanding is correct, a syntax object contains at least a piece of literal program and the binding information of the symbols within it.

It is worth having the following in mind:

A syntax object represents a program (or a piece of a program).  
Macro expansion is a process that begins with a syntax object with no (or limited) binding information. During macro expansion the bindings structure is discovered and bindings information is added to the output of the macro expansion (also a syntax object).  
The information available during the expansion might only be partial.

I can recommend watching the first 10-15 minutes of Flatt's talk "Let's Build a Hygienic Macro Expander". The introduction is all about scopes and how they are represented.

[![](https://global.discourse-cdn.com/free1/uploads/racket/original/2X/0/0e2dda3d09b350e49005eb3bd6292899bb5e72fe.jpeg ""Let's Build a Hygienic Macro Expander" by Matthew Flatt") ](https://www.youtube.com/watch?v=Or_yKiI3Ha4)

FWIW the documentation for `#'` aka `quote-syntax` is here:

[https://docs.racket-lang.org/reference/Syntax\_Quoting\_\_quote-syntax.html#(form.\_((quote.\_~23~25kernel).\_quote-syntax))](https://docs.racket-lang.org/reference/Syntax_Quoting__quote-syntax.html#%28form._%28%28quote._~23~25kernel%29._quote-syntax%29%29)

---

<div class="post-metadata">

**Author:** ![usao](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/usao/32/1375_2.png) [@usao](https://racket.discourse.group/u/usao)\
**Post date:** [February 22, 2024, 1:39am UTC](https://racket.discourse.group/t/some-basic-questions-about-macros-and-scope/2731/3 "2024-02-22T01:39:25Z")

</div>

The `syntax` form, or rather, `quote-syntax` form (without `#:local`) performs what is called “scope pruning”, “capturing” up to a certain point, otherwise the use of binding forms in macros will be impossible.

---

<div class="post-metadata">

**Author:** ![neteroster](https://avatars.discourse-cdn.com/v4/letter/n/eada6e/32.png) [@neteroster](https://racket.discourse.group/u/neteroster)\
**Post date:** [February 22, 2024, 11:31am UTC](https://racket.discourse.group/t/some-basic-questions-about-macros-and-scope/2731/4 "2024-02-22T11:31:32Z")

</div>

@soegaard @usao

Thank you! I've learned a lot from your answers.
