[plt-scheme] Null syntax / Conditional definition

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Fri Jun 24 09:15:21 EDT 2005

At Mon, 20 Jun 2005 01:53:37 +0900, Chihiro Kuraya wrote:
> -----------------------------------------------------------------------
> (module m1 mzscheme
>   (provide if-for-syntax)
>   (define-syntax (if-for-syntax stx)
>     (syntax-case stx ()
>       ((_ TEST THEN ELSE)
>        (if (eval #'TEST)
>            #'THEN
>            #'ELSE))))
>   )
> (module m2 mzscheme
>   (require m1)
>   (define OS 'windows)
>   (if-for-syntax (eq? OS 'windows)
>     (begin
>       (define OS-name "Windows"))
>     (begin
>       (define OS-name "Unknown")))
>   )
> -----------------------------------------------------------------------
> But the following error message was displayed.
> -----------------------------------------------------------------------
> require: broken compiled code (phase 0, defn-phase 0): 
> cannot find module m2 in: OS
> -----------------------------------------------------------------------
> I can't understand why this code doesn't work
> and what means this error message.
> Doesn't #'TEST syntax object have lexical context which 
> contains OS identifier ?

The identifier `OS' does not correspond to a binding until the module
`m' is evaluated, and the module `m' is not evaluated until after all
of it's expressions are expanded. In other words, there's a phase
separation between compile time (when the module is expanded) and run
time (when the module is executed and its internal bindings exist).

The error message from `eval' is not great, but `eval' provides an
inherently strange bridge between phases. Just avoid `eval'.

The code below shows how to do what you want (I think) in a
phase-friendly manner. The `OS' binding is a for-syntax binding, so it
can be used at compile time. The `if-for-syntax' macro expands so that
the test ends up in a compile-time position that selects the THEN or
ELSE run-time branch. (The intermediate `result' macro essentially
plays the role of a compile-time `eval', but it explicitly shifts the
expression to compile time.)



(module m1 mzscheme
  (provide if-for-syntax)
  (define-syntax (if-for-syntax stx)
    (syntax-case stx ()
      ((_ TEST THEN ELSE)
	   (define-syntax (result stx)
	     (syntax-case stx ()
	       [(_ t e)
		(if TEST
	   (result THEN ELSE)))))

(module m2 mzscheme
  (require m1)
  (define-for-syntax OS 'windows)

  (if-for-syntax (eq? OS 'windows)
      (define OS-name "Windows"))
      (define OS-name "Unknown")))

Posted on the users mailing list.