[plt-scheme] Injecting syntax into load

From: Norman Gray (norman at astro.gla.ac.uk)
Date: Sun Dec 10 12:52:31 EST 2006

Danny, hello.

On 2006 Dec 7 , at 18.16, Danny Yoo wrote:

> On Thu, 7 Dec 2006, Norman Gray wrote:
>> Can anyone tell me how I would inject new syntax into the syntax  
>> transformer used by LOAD, in such a way that REQUIRE in the loaded  
>> file works?
> Here's an example that might help:

Hero!  Thanks for this -- it's extremely helpful.

> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (module test mzscheme
> [...]

> Namespaces affect EVAL, so whenever we want to do something with  
> them, we either need to use the namespace-specific functions, or  

The following variant of your snippet made the discinction a little  
clearer to me:

(define n-expr 0)
(define (inc-n)
   (set! n-expr (+ n-expr 1)))
(parameterize ([current-namespace (make-namespace)])
   (namespace-transformer-require 'mzscheme)
   (eval `(define another ,inc-n))  ; change
       (define-syntax (double stx)
         (syntax-case stx ()
           [(_ x)
            (syntax/loc stx
              (begin (another)  ; change
                     (list x x)))]))))
   (let loop ([s-expr (read)])
     (cond [(eof-object? s-expr) 'done]
            (display (format "~a: ~a~%" n-expr (eval s-expr)))
            (loop (read))])))
(display (format "~a doubles evaluated~%" n-expr))


Thus even within the parameterised namespace, the non-EVALed  
expressions are still acquiring the bindings of the `parent'  
environment; it's only EVAL (and, as you say, LOAD) that evaluates  
things in the new namespace.  I wasn't getting this (as well as not  
twigging the significance of namespace-transformer-require).

That's intelligible in retrospect: this is exactly what the  
documentation for EVAL says (in Section 14.1); what I'm only now  
understanding is that this is a contentful remark, since it is  
distinct from the reading-and-evaluating being done as this  
expression as a whole is read.

I see a clue coming (thud!): when the PARAMETERIZE expression is  
read, that reading is done, syntax is expanded, and the identifiers  
bound, in the environment in which INC-N is defined.  When the EVALs  
are evaluated, however, that's done in the fresh environment/ 
namespace in which INC-N is not defined.  Omitting the PARAMETERIZE,  
and having the call to CURRENT-NAMESPACE at the top level, breaks the  
above example, for reasons which I now (think I) understand.

Scheme _is_ simple, isn't it...

Thanks again for the insight.  Best wishes,


Norman Gray  /  http://nxg.me.uk
eurovotech.org  /  University of Leicester, UK

Posted on the users mailing list.