Ah yes, this is an annoying part of structs. The definition of the struct-type 
also takes in the properties it will have, so the accessors are not defined at 
the point of property definition. If you use the identifier without 
eta-expanding it (i.e. if foo takes two arguments, its eta-expansion is (lambda 
(x y) (foo x y))), then Racket will try to evaluate it, but it's not defined 
yet -- oops.

A way to get around this, since you know it's a field accessor, is to generate 
a temporary name that is the eta-expansion, and use that in the prop:inners.

(define-syntax (struct-abc stx)
    (syntax-case stx ()
      [(_ sname (name args ...) props ...)
       (with-syntax* ([sname-name (format-id #'sname "~a-~a" #'sname #'name)]
                      [temp (generate-temporary #'sname-name])
       #`(begin
          (struct sname (name args ...) props ...
           #:property prop:insiders temp)
          (define (temp x) (sname-name x))))]))

-Ian

----- Original Message -----
From: "antoine" <[email protected]>
Cc: [email protected]
Sent: Tuesday, September 3, 2013 1:17:40 PM GMT -05:00 US/Canada Eastern
Subject: Re: [racket] Binding undefined with a macro

I have grasp the problem i have expanded the file and narrow the region 
concerned and get :

(define-values
     (struct:person person1 person? person-name person-nickname) ; 
define here
     (let-values (((struct: make- ? -ref -set!)
                   (let-values ()
                     (let-values ()
                       (#%app
                        make-struct-type
                        'person
                        '#f
                        '2
                        '0
                        '#f
                        (#%app list (#%app cons prop:insiders 
person-name)) ; accessed here
                        (#%app current-inspector)
                        '#f
                        '(0 1)
                        '#f
                        'person)))))
       (#%app
        values
        struct:
        make-
        ?
        (#%app make-struct-field-accessor -ref '0 'name)
        (#%app make-struct-field-accessor -ref '1 'nickname))))

We see that person-name is accessed before it definition.

So i rewrite the macro :

(define-syntax (struct-abc stx)
    (syntax-case stx ()
      [(_ sname (name args ...) props ...)
       (with-syntax ([sname-name (format-id #'sname "~a-~a" #'sname 
#'name)])
       #`(struct sname (name args ...) props ...
           #:property prop:insiders sname-name))]))

to :

(define-syntax (struct-abc stx)
    (syntax-case stx ()
      [(_ sname (name args ...) props ...)
       (with-syntax ([sname-name (format-id #'sname "~a-~a" #'sname 
#'name)])
       #`(struct sname (name args ...) props ...
           #:property prop:insiders (lambda () sname-name)))]))


I don't know if there is another way to do this sort of recursive 
binding without a lambda.

Thanks for you reply it helps me point out the problem.

On 03/09/2013 18:36, J. Ian Johnson wrote:
> The struct form generates names unhygienically, but predictably. You will 
> have to have a handle on both the struct name and field name to produce an 
> identifier equal to the generated field accessor.
> In your case, if you can commit to name always being given first (there are 
> ways around this that involve more parsing), then the following will allow 
> you to write your macro correctly:
>
> (require (for-syntax racket/syntax))
> (define-syntax (struct-abc stx)
>     (syntax-case stx ()
>       [(_ sname (name args ...) props ...)
>        (with-syntax ([sname-name (format-id #'sname "~a-~a" #'sname #'name)])
>        #`(begin
>        (+ 1 1)
>        (struct sname (name args ...) props ...
>            #:property prop:insiders sname-name)))]))
>
> -Ian
> ----- Original Message -----
> From: "antoine" <[email protected]>
> To: [email protected]
> Sent: Tuesday, September 3, 2013 12:23:17 PM GMT -05:00 US/Canada Eastern
> Subject: [racket] Binding undefined with a macro
>
> Hello,
>
> With this macro:
>
> (define-syntax (struct-abc stx)
>     (syntax-case stx ()
>       [(_ name (args ...) props ...)
>        #`(begin
>        (+ 1 1)
>        (struct name (args ...) props ...
>            #:property prop:insiders person-name))]))
>
> (define-values (prop:insiders insiders? insiders-ref)
>     (make-struct-type-property 'insider))
>
>
> When i do :
>
> (struct-abc person (name nickname))
>
> I get :
>
> person-name: undefined;
>    cannot reference an identifier before its definition
>
> But i know that person-name is defined the problem come from 'begin' in
> the macro, if i rewrite like this :
>
> (define-syntax (struct-abc stx)
>     (syntax-case stx ()
>       [(_ name (args ...) props ...)
>        #`(struct name (args ...) props ...
>            #:property prop:insiders person-name)]))
>
> It works as expected.
>
> So my question are:
>
> Could you explain (point out) me why the person-name is unknown at this
> point?
> And how can i change the begin with something like '#,@'?
>
> Thank you.
> ____________________
>    Racket Users list:
>    http://lists.racket-lang.org/users

____________________
  Racket Users list:
  http://lists.racket-lang.org/users
____________________
  Racket Users list:
  http://lists.racket-lang.org/users

Reply via email to