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