[plt-scheme] Evaluation Across Modules (or Namespaces?)

From: Williams, M. Douglas (M.DOUGLAS.WILLIAMS at saic.com)
Date: Sun Jul 16 13:12:23 EDT 2006

I am having a problem understanding how eval works across modules and/or
namespaces.  I have distilled my problem down to a fairly simple set of
examples.

At the top level, the following works (s is a structure to hold a
definition, def is a definition macro, act activates an instance of s
(creates a procedural object dynamically, app applies it).  [In the actual
application, the args cannot be easily computed at expansion time and act
may create multiple instances with different args.  In any case, I can't
easily create the procedural object in the macro.]

(define-struct s (args body f))

(define-syntax def
  (syntax-rules ()
    ((d name args body ...)
     (define name (make-s 'args
                          '(body ...)
                          #f)))))

(define (act an-s)
  (set-s-f! an-s
            (eval `(lambda ,(s-args an-s)
                     ,@(s-body an-s)))))

(define (app an-s . args)
  (apply (s-f an-s) args))

(define (my-f3 x) (* x x))

(def t1 (x) (* x x))
(act t1)
(printf "(app(t1 2) = ~a~n" (app t1 2))

(define (my-f2 x) (* x x))
(def t2 (x) (my-f2 x))
(act t2)
(printf "(my-f2 2) = ~a~n" (my-f2 2))
(printf "(app(t2 2) = ~a~n" (app t2 2))

(def t3 (x) (my-f3 x))
(act t3)
(printf "(my-f3 2) = ~a~n" (my-f3 2))
(printf "(app(t3 2) = ~a~n" (app t3 2))

If I run it, I get:

(app(t1 2) = 4
(my-f2 2) = 4
(app(t2 2) = 4
(my-f3 2) = 4
(app(t3 2) = 4

Which is what I want.  However, I'd like to have the application part in a
module to be used by other modules.  I created two modules a and b:  [The
my-f3 definition in module a is just to have something callable in that
module.]

(module a mzscheme
  
  (provide (all-defined))
  
  (define-struct s (args body f))
  
  (define-syntax def
    (syntax-rules ()
      ((d name args body ...)
       (define name (make-s 'args
                            '(body ...)
                            #f)))))
  
  (define (act an-s)
    (set-s-f! an-s
              (eval `(lambda ,(s-args an-s)
                       ,@(s-body an-s)))))
  
  (define (app an-s . args)
    (apply (s-f an-s) args))
  
  (define (my-f3 x) (* x x))
  
  )

(module b mzscheme
  
  (provide (all-defined))
  
  (require "a.ss")
  
  (def t1 (x) (* x x))
  (act t1)
  (printf "(app(t1 2) = ~a~n" (app t1 2))
  
  (define (my-f2 x) (* x x))
  (def t2 (x) (my-f2 x))
  (act t2)
  (printf "(my-f2 2) = ~a~n" (my-f2 2))
  (printf "(app(t2 2) = ~a~n" (app t2 2))
    
  (def t3 (x) (my-f3 x))
  (act t3)
  (printf "(my-f3 2) = ~a~n" (my-f3 2))
  (printf "(app(t3 2) = ~a~n" (app t3 2))

  )

And get this when I run it:

(app(t1 2) = 4
(my-f2 2) = 4
. . a.ss::436: reference to undefined identifier: my-f2

So, it seems to only work for identifiers (like *) in the mzscheme
namespace.  If I comment out the middle part of module b using a local
definition to b, I get the following:

(app(t1 2) = 4
(my-f3 2) = 4
. . a.ss::436: reference to undefined identifier: my-f3

So it doesn't seem to be evaluated in the namespace for a (where my-f3 is
defined either).

I hoped I could capture b's name space using (current-namespace) in the
macro expansion and parameterize in act as follows:

(module a1 mzscheme
  
  (provide (all-defined))
  
  (define-struct s (args body f ns))
  
  (define-syntax def
    (syntax-rules ()
      ((d name args body ...)
       (define name (make-s 'args
                            '(body ...)
                            #f
                            (current-namespace))))))
  
  (define (act an-s)
    (parameterize ((current-namespace (s-ns an-s)))
      (set-s-f! an-s
                (eval `(lambda ,(s-args an-s)
                         ,@(s-body an-s))))))
  
  (define (app an-s . args)
    (apply (s-f an-s) args))
  
  (define (my-f3 x) (* x x))
  
  )

(module b1 mzscheme
  
  (provide (all-defined))
  
  (require "a1.ss")
  
  (def t1 (x) (* x x))
  (act t1)
  (printf "(app(t1 2) = ~a~n" (app t1 2))
  
  (define (my-f2 x) (* x x))
  (def t2 (x) (my-f2 x))
  (act t2)
  (printf "(my-f2 2) = ~a~n" (my-f2 2))
  (printf "(app(t2 2) = ~a~n" (app t2 2))
    
  (def t3 (x) (my-f3 x))
  (act t3)
  (printf "(my-f3 2) = ~a~n" (my-f3 2))
  (printf "(app(t3 2) = ~a~n" (app t3 2))

  )

But the results are identical.

Can someone enlighten me as to the error of my ways?  The example code is in
the attached files.

Doug

-------------- next part --------------
A non-text attachment was scrubbed...
Name: top.ss
Type: application/octet-stream
Size: 725 bytes
Desc: not available
URL: <http://lists.racket-lang.org/users/archive/attachments/20060716/04e1bbd6/attachment.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: a.ss
Type: application/octet-stream
Size: 498 bytes
Desc: not available
URL: <http://lists.racket-lang.org/users/archive/attachments/20060716/04e1bbd6/attachment-0001.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: b.ss
Type: application/octet-stream
Size: 426 bytes
Desc: not available
URL: <http://lists.racket-lang.org/users/archive/attachments/20060716/04e1bbd6/attachment-0002.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: a1.ss
Type: application/octet-stream
Size: 609 bytes
Desc: not available
URL: <http://lists.racket-lang.org/users/archive/attachments/20060716/04e1bbd6/attachment-0003.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: b1.ss
Type: application/octet-stream
Size: 428 bytes
Desc: not available
URL: <http://lists.racket-lang.org/users/archive/attachments/20060716/04e1bbd6/attachment-0004.obj>

Posted on the users mailing list.