[racket] Structs and syntax-local-value ... how is the struct name overloaded?

From: Alexander D. Knauth (alexander at knauth.org)
Date: Mon Jan 20 10:13:57 EST 2014

I'm just curious, is this what you mean?

#lang racket

(require rackunit
          (for-syntax
           syntax/parse))

(begin-for-syntax
   (struct proc-with-info (proc info) #:property prop:procedure  
(struct-field-index proc)))

(define-syntax thing
   (proc-with-info (lambda (stx)
                     (syntax-parse stx #:literals (thing)
                                   [(thing x ...)
                                    #'(#%app thing x ...)]
                                   [thing
                                    #'(lambda (x) x)]))
                   'info))

(define-syntax get-info
   (lambda (stx)
     (syntax-parse stx
                   [(get-info x)
                    (datum->syntax stx `(quote ,(proc-with-info-info  
(syntax-local-value #'x))))])))

(check-equal? (thing 1) 1)
(let ([x (random)])
   (check-equal? (thing x) x))

(check-equal? (get-info thing)
               'info)


On Jan 20, 2014, at 12:37 AM, Carl Eastlund wrote:

> It sounds like you've got it.  A syntax transformer must be a  
> procedure, and prop:procedure is how you make a procedure that can  
> also be something else.  So if you want something to be both a  
> syntax transformer and a struct binding, for instance, you need to  
> use prop:procedure and prop:struct-info.  You can't make something  
> both a procedure and a symbol, because symbols don't work via struct  
> properties, but you could make it both a procedure and a struct that  
> contains a symbol.
>
> Carl Eastlund
>
> On Mon, Jan 20, 2014 at 12:21 AM, Scott Klarenbach  
> <scott at pointyhat.ca> wrote:
> That doesn't look like a complete program; what does #'done refer  
> to?  And where did the "val is: " printout go?
>
> That's just a quick hack for illustration purposes.  #''done is just  
> something to return. (note the two quotes)  The output is:
> val is: #<procedure:self-ctor-checked-struct-info>#<procedure:posn>
> 'done
>
> But your supposition is correct: posn is always bound as syntax to a  
> self-ctor-checked-struct-info-object.  That object works as a syntax  
> transformer; run time references to posn are transformed into  
> references to the actual procedure value you're seeing as  
> #<procedure:posn>.
>
> Thanks Carl, it's starting to make sense.  So the prop:procedure of  
> the struct is actually the transformer?  And so in expression  
> context it acts as a macro, but in syntax-local-value context it  
> acts as a struct?  I was trying to produce something similar, but  
> ran into the following issues:
>
> Say I want (define-syntax (posn) ...) to transform syntax, but I  
> also want (syntax-local-value #'posn) to return 'something.
> Without the struct trick I can only have one but not the other.  I  
> could either have (define-syntax posn 'something), and lose the  
> ability to call it as a macro (illegal syntax), or have (define- 
> syntax (posn) #'something), and then (syntax-local-value #'posn)  
> returns the transformer, rather than 'something.
>
>
>
>
>
> On Sun, Jan 19, 2014 at 8:57 PM, Scott Klarenbach  
> <scott at pointyhat.ca> wrote:
> It's not changing it, I'm just trying to figure out the  
> implementation and understand what I'm seeing.
> For example, given this:
>
> (struct posn (x y))
>
> (define-syntax (test stx)
>   (syntax-case stx ()
> 	[(_ x)
> 	 (printf "val is: ~s" (syntax-local-value #'posn))
> 	 #''done]))
>
> > posn
> #<procedure:posn>
>
> > (test x)
> #<procedure:self-ctor-checked-struct-info>
>
> I'm surprised that the values are different.  Is posn actually  
> always a self-ctor-checked-struct-info object, but it's  
> prop:procedure is defined to allow for being used in an expression  
> in the first case?
>
>
>
>
> On Sun, Jan 19, 2014 at 8:40 PM, Carl Eastlund <carl.eastlund at gmail.com 
> > wrote:
> If syntax-local-value is returning something other than the value  
> you put in, that's a bug.  It shouldn't be wrapping it or changing  
> it in any way.  Do you have a program where you bind something via  
> define-syntax that satisfies struct-info?, and get something out via  
> syntax-local-value that doesn't?
>
> Carl Eastlund
>
> On Sun, Jan 19, 2014 at 11:27 PM, Scott Klarenbach  
> <scott at pointyhat.ca> wrote:
> But I don't see how the same binding can be a transformer and also  
> return something else (like a list, or a checked-struct-info-thing)  
> via syntax-local-value.
>
> If I bind my-fn as a transformer, then any other macros that use it  
> with syntax-local-value will receive the transformer procedure back,  
> not any special meta data.  And if I bind it as meta data directly,  
> ie (define-syntax my-fn 'something) then it works with syntax-local- 
> value but any attempts to use it as a transformer result in illegal  
> syntax.
>
> Even if I create a transformer that returns a struct which  
> implements both prop:procedure and prop:struct-info, using that  
> binding with syntax-local-value will return the transformer  
> procedure itself, rather than the final struct.
>
>
>
> On Sun, Jan 19, 2014 at 8:04 PM, Carl Eastlund <carl.eastlund at gmail.com 
> > wrote:
> Yes, I believe that the name of a structure defined by "struct" is  
> bound at syntax-time to a value that implements both prop:procedure,  
> so that it can expand to a use of the constructor when used in an  
> expression, and prop:struct-info so that it can be use to look up  
> static information when passed to relevant macros.
>
> Carl Eastlund
>
>
> On Sun, Jan 19, 2014 at 11:00 PM, Scott Klarenbach  
> <scott at pointyhat.ca> wrote:
> How is it that the definition of (struct my-name (x y)) can bind my- 
> name both as a #<procedure:my-name> at runtime and a transformer- 
> binding my-name that at compile time (via syntax-local-value)  
> produces #<procedure:self-ctor-checked-struct-info>.?
>
> Or, put another way, how can I define a transformer my-fn that  
> produces syntax, but that also exposes hidden meta-data under the  
> same binding to other macros that might wish to know about the  
> binding at compile time?
>
> I'm specifically wondering how the overloading works.  Is it some  
> clever use of prop:procedure?
>
> Thanks.
>
> -- 
> Talk to you soon,
>
> Scott Klarenbach
>
> PointyHat Software Corp.
> www.pointyhat.ca
> p 604-568-4280
> e scott at pointyhat.ca
> 200-1575 W. Georgia
> Vancouver, BC V6G2V3
>
> _______________________________________
> To iterate is human; to recur, divine
>
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users
>
>
>
>
>
> -- 
> Talk to you soon,
>
> Scott Klarenbach
>
> PointyHat Software Corp.
> www.pointyhat.ca
> p 604-568-4280
> e scott at pointyhat.ca
> 200-1575 W. Georgia
> Vancouver, BC V6G2V3
>
> _______________________________________
> To iterate is human; to recur, divine
>
>
>
>
> -- 
> Talk to you soon,
>
> Scott Klarenbach
>
> PointyHat Software Corp.
> www.pointyhat.ca
> p 604-568-4280
> e scott at pointyhat.ca
> 200-1575 W. Georgia
> Vancouver, BC V6G2V3
>
> _______________________________________
> To iterate is human; to recur, divine
>
>
>
> -- 
> Talk to you soon,
>
> Scott Klarenbach
>
> PointyHat Software Corp.
> www.pointyhat.ca
> p 604-568-4280
> e scott at pointyhat.ca
> 200-1575 W. Georgia
> Vancouver, BC V6G2V3
>
> _______________________________________
> To iterate is human; to recur, divine
>
> ____________________
>  Racket Users list:
>  http://lists.racket-lang.org/users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20140120/5774cdb8/attachment-0001.html>

Posted on the users mailing list.