[racket] Understanding lexical context

From: Greg Hendershott (greghendershott at gmail.com)
Date: Tue Oct 1 14:01:07 EDT 2013

During RacketCon someone said they were having trouble
trying to build on an example from Fear of Macros. Below is
a distilled version.

They were trying to use my example macro `inner` in their
macro `outer`. My original version of `inner` supplied the
wrong value for `lctx` in `datum->syntax`, e.g. `#'a`. I got
it to work by changing that to `#'body0`. I also
experimented with other values, none of which worked:

    #lang racket

    (require (for-syntax racket/syntax))

    (define-syntax (inner stx) ;; "hyphen-define"
      (syntax-case stx ()
        [(k a b (args ...) body0 body ...)
         (let (#;[lctx stx] ;There ish no pleashing you.
               #;[lctx #'k] ;There ish no pleashing you.
               #;[lctx #'a] ;There ish no pleashing you.
               [lctx #'body0]) ;Oh yesh. This is a keeper.
           (with-syntax ([name (format-id lctx "~a-~a" #'a #'b)])
             #'(define (name args ...)
                 body0 body ...)))]))

    (define-syntax (outer stx)
      (syntax-case stx ()
        [(_ name v)
         #'(begin
             (define name v)
             (inner get name () name))]))

    ;; Use `inner` directly:
    (inner yesh shalty (x) x)
    (yesh-shalty "hi") ;; => "hi"

    ;; Use `inner` indirectly, via `outer`:
    (outer schmoke-und-a-pancake? "hi")
    schmoke-und-a-pancake?       ;; => "hi"
    (get-schmoke-und-a-pancake?) ;; undefined if wrong `lctx` in `inner`

(Quoting Goldmember from Austin Powers is just a mindhack;
laugh don't cry.)

So I need to update Fear of Macros. I need to fix the
example. More importantly, I ought to explain _why_ this
matters, and _how_. But my grasp of "lexical context" is
still poor, apparently.

I've (re)read the following this morning, searching for
explanations:

- Jay's blog post, "The Underbelly of Racket Macro Basics":
http://jeapostrophe.github.io/2013-07-22-123list-post.html

- Eli's blog post, "Writing 'syntax-case' Macros:
http://blog.racket-lang.org/2011/04/writing-syntax-case-macros.html

- I even looked at Dybvig's paper, "Syntactic Abstraction in Scheme":
http://www.cs.indiana.edu/~dyb/pubs/LaSC-5-4-pp295-326.pdf

Each mentioned that it's important to choose the lexical
context. Eli even alluded to exactly the use case of macros
generating macros. But somehow I wasn't able to come away
with a crisp mental model, much less a "recipe" for how to
reason about examples.

In this particular example: The worst I could say is, "I
tried all the options until one worked." Cough. The best I
could say (at the moment) is, "The reason why `body0` syntax
is the correct choice is because that syntax originated from
the use of `outer`, which is where the name we create needs
to be visible". Is that it -- is it really simply a matter
of thinking through where the bits of syntax originate?

Are there discussions or examples that predate Racket? (I
checked Dybvig's paper with the guess that this issue is
something already obvious to advanced Racketeers from
previous experience. But even if so, maybe I overlooked
other such resources.)

tl;dr: Can anyone suggest how I could improve my
understanding of this?  Enough that I could improve Fear of
Macros and help others, too? Thanks in advance.

Posted on the users mailing list.