[racket] scoping rules and define-for-syntax

From: Shriram Krishnamurthi (sk at cs.brown.edu)
Date: Sat Jul 24 22:42:53 EDT 2010

I don't quite know where to read to understand, and to work around,
the following scoping rules.

Here's a very simple module (details not important, only the functions
being define-for-syntax'd):

  (module my-new-syntax racket

    (provide (except-out (all-from-out racket) lambda)
	     (rename-out (my-lambda lambda)))

    (require (for-syntax racket))

    (define-for-syntax (f3 e)

    (define-syntax (my-lambda e)
      (syntax-case e ()
	[(_ arg body) ;; _ is lambda
	 (with-syntax ([not-transformed-body (f3 (syntax body))])
	   (syntax (lambda arg not-transformed-body)))])))

If I load this module and run run

  (module tester 'my-new-syntax
    (define f (lambda (x) x x)))

in the definitions window I get a syntax error, whereas for

  (module tester 'my-new-syntax
    (define f (lambda (x) x)))

I don't.  So far, so good.

However, if I change the source of my-new-syntax to be

  (module my-new-syntax racket

    (provide ... same as before ...)

    (require ... same as before ...)

    (define-for-syntax (f1 e)
      (f3 e))

    (define-for-syntax (f3 e)

    (define-syntax (my-lambda e) ... same as before ...))

and Run, I get

expand: unbound identifier in module (in phase 1, transformer
environment) in: f3

highlighting the use inside f1.  If I swap the order of definitions of
f1 and f3, this works fine.

This, however, is just an illustrative simplification of my real
program, which has non-trivial mutually-referential functions.  The
only solution I have is effectively

  (define-for-syntax (shell e)

    (define (f1 e) ...)
    (define (f3 e) ...)

    (f3 e))

which works, but is pretty unsatisfactory.


Posted on the users mailing list.