[plt-scheme] create complex object @ compile time but made available @ run time?

From: Jens Axel Søgaard (jensaxel at soegaard.net)
Date: Wed Jun 13 03:27:24 EDT 2007

YC skrev:

> But this does not hold for complex object such as struct with the 
> following code - is this something wrong with the code or is it 
> something else?

The problem here is not that it is a complex object, but that
structure definitions are generative - it would have worked
if you used vectors. Back to the structure problem. To quote the

   "Each time a define-struct expression is evaluated, a new structure
    type is created with distinct constructor, predicate, accessor, and
    mutator procedures."

Consider this example, where the foo struct type is defined twice:

(define-values (make1 get1)
   (let ()
     (define-struct foo (vals) (make-inspector))
     (values make-foo foo-vals)))

(define-values (make2 get2)
   (let ()
     (define-struct foo (vals) (make-inspector))
     (values make-foo foo-vals)))

 > (make1 42)
#(struct:foo 42)
 > (make2 42)
#(struct:foo 42)
 > (get1 (make1 42))
 > (get2 (make1 42))
[bug] foo-vals: expects args of type <struct:foo>; given instance of a
different <struct:foo>

Notice the last error, which is the same as you saw. In your example
the problem is more diffcult to spot, but it is the same problem.
The reason is that (define-struct foo (vals)) is run twice. The
first time, when foo is required for the normal environment with
(require foo). The second time, when you require it for the
syntax-environment with (require-for-syntax foo). That is, even
though the structs in the runtime and the syntax environment have
the same name, they are in fact different.

One solution is to calculate the values at expansion time, and
then expand to (create-foo val1 ...).

(module foo mzscheme
   (define-struct foo (vals) (make-inspector)) ; inspector for debug
   (define (create-foo . vals)
     (make-foo vals))
   (provide (all-defined)))

(require foo)

(define-syntax (macro-foo stx)
   (syntax-case stx ()
     ((_ val1 val2 ...)
      (with-syntax (((val ...)
                     (map (lambda (n) (add1 (syntax-object->datum n)))
                          (syntax->list #'(val1 val2 ...)))))
        #`(create-foo val ...)))))

(define f1 (macro-foo 1 2 3))
f1 ; => shows #<struct:foo (2 3 4)>
(foo? f1) ; => #t
(foo-vals f1) ; => (2 3 4)

Jens Axel Søgaard

Posted on the users mailing list.