Thanks very much, Matt. This is helpful. 

I understand macros in a general way (I'm an old [very old] Scheme hand, 
plus I use Mathematica every day, and it's almost nothing but macros). 
However, the particulars of Racket's hygienic macro system are new to me, 
and I will read-up on all the references you sent. 

Once again, thanks very much for your kind attention and generous expense 
of time. I'm doing a lot of barnstorming (using educated guesswork) in 
trying to build stuff quickly, and targeted, bottom-up reading such as you 
suggest is very a-propos and helpful at quick-starting me and my team. 
Racket got very big, but in a good way, since I last looked at it 20 years 
ago.

On Sunday, October 31, 2021 at 9:59:58 AM UTC-7 Matt Jadud wrote:

> Hi Brian,
>
> In some ways, you did get a very good answer to your first question. You 
> were able to see the properties of a *syntax object*. But syntax objects 
> were, I think, only part of the picture you were looking for.
>
> The questions "what does the *struct* form in Racket do, what bindings 
> does it introduce into the namespace, at what point in the macro-expansion 
> tower do those things happen, and how can I understand the mechanisms that 
> are at work in that expansion?" are... different questions, as you 
> discovered.
>
> If you're keen to understand the Racket macro system (not knowing your 
> background; apologies if this is all old news):
>
> * Matthew B's *Beautiful Racket* has a nice section on Macros: 
> https://beautifulracket.com/explainer/macros.html
> * Flatt's *Let's Build a Hygenic Macro Expander *will provide a 
> conceptual foundation that aligns with Racket's macro expander: 
> https://www.youtube.com/watch?v=Or_yKiI3Ha4
> * Hendershott's *Fear of Macros *has an intimidating cat, and dives 
> deeper into the Racket tools of macro construction: 
> https://www.greghendershott.com/fear-of-macros/
> * Clinger and Wand's *Hygenic Macro Technology* is a brief (100p) walk 
> through the history of macro expansion systems in the Scheme world: 
> https://dl.acm.org/doi/pdf/10.1145/3386330
>
> These materials (in particular, Matthew's talk) might help give a sense 
> for what is involved in pulling back the curtain on a macro expansion, and 
> the kind of implementation details that are going on under the hood.
>
> I would say that studying the code for *struct-plus-plus* could also be 
> informative, as it would provide a way to see how a struct system that 
> provides the kind of visibility you were looking for achieves that 
> visibility, and how it interacts with the macro expansion tower.
>
> Cheers,
> Matt
>
>
> On Sun, Oct 31, 2021 at 11:52 AM Brian Beckman <[email protected]> wrote:
>
>> Hi, Matt ... I'll try your ideas in a little while. 
>>
>> Regarding "why," I want the ability, from a module or a REPL, to quickly 
>> dump the attributes of an instance without having to look things up. The 
>> need arose when I was barnstorming and trying to explain syntax objects to 
>> someone, and he asked "what are the attributes of a syntax object?" I 
>> replied, "let's just dump one out," and that turned out impossible. So we 
>> did an F1 lookup of the doc and were confronted with the general 
>> meta-syntactic definition 
>> file:///usr/share/doc/racket/reference/stx-patterns.html#%28form._%28%28lib._racket%2Fprivate%2Fstxcase-scheme..rkt%29._syntax%29%29.
>>  
>> Well, we weren't going to finish understanding that in the one-hour lunch 
>> meeting we had.
>>
>> Bottom line, I was unable to give a quick answer to a reasonable question.
>>
>> On Sunday, October 31, 2021 at 3:42:19 AM UTC-7 Matt Jadud wrote:
>>
>>> Hi Brian,
>>>
>>> Does this help move you forward?
>>>
>>> It has been a while since I've stared at macros in Racket, so this might 
>>> be easier... 
>>>
>>> Also, make sure you're executing this code in a module. If you're 
>>> working in a REPL, I suspect all bets are off. It is certainly the case 
>>> that you could combine several of my exploration steps into a 
>>> simpler/cleaner macro, instead of generating lists of symbols, converting 
>>> them back to syntax objects, and so on.
>>>
>>> Also, as a solution/exploration, I... don't know how this would interact 
>>> with the full range of possible structs. Someone who knows more about 
>>> syntax and structs should be able to speak to how you'd find out all of the 
>>> defined functions that spawn from struct definition/creation. (It might 
>>> also be useful to know *why* you want to destructure structs this way? 
>>> Knowing that may illuminate some other path forward.)
>>>
>>> #lang racket
>>> (require racket/struct-info)
>>>
>>> (struct A (b c))
>>>
>>> (struct B (e f) #:transparent)
>>>
>>> (require (for-syntax racket/struct-info))
>>> (define-syntax (get-field-names stx)
>>>   (syntax-case stx ()
>>>     [(_ sym)
>>>      #`(quote
>>>         #,(struct-field-info-list
>>>            (syntax-local-value #'sym)))
>>>               ]))
>>>
>>> ;; These let me see the field names
>>> (get-field-names A)
>>> ;; Returns '(c b)
>>> (get-field-names B)
>>> ;; Returns '(f e)
>>>
>>> ;; 
>>> https://stackoverflow.com/questions/20076868/how-to-know-whether-a-racket-variable-is-defined-or-not
>>> (define-syntax (defined? stx)
>>>   (syntax-case stx ()
>>>     [(_ id)
>>>      (with-syntax ([v (identifier-binding #'id)])
>>>        #''v)]))
>>>
>>> (define-syntax (proc-names stx)
>>>   (syntax-case stx ()
>>>     [(_ sym)
>>>      (let ([names (map (λ (s)
>>>                          (string->symbol
>>>                           (format "~a-~a" (syntax-e #'sym) s)))
>>>                        (struct-field-info-list
>>>                         (syntax-local-value #'sym))
>>>                        )])
>>>        #`(quote #,names))]))
>>>
>>> ;; This...
>>> (proc-names A)
>>> ;; Returns '(A-c A-b)
>>>
>>> (define-syntax (names-exist? stx)
>>>   (syntax-case stx ()
>>>     [(_ sym)
>>>      (let ([names (map (λ (s)
>>>                          (string->symbol
>>>                           (format "~a-~a" (syntax-e #'sym) s)))
>>>                        (struct-field-info-list
>>>                         (syntax-local-value #'sym))
>>>                        )])
>>>        #`(andmap (λ (s)
>>>                    (equal? 'lexical s))
>>>                  (map (λ (s)
>>>                         (defined? s))
>>>                       (quote #,names)))
>>>        )]))
>>>
>>> (names-exist? A)
>>> (names-exist? B)
>>>
>>>
>>> On Sat, Oct 30, 2021 at 10:33 PM Brian Beckman <[email protected]> 
>>> wrote:
>>>
>>>> Here are some of my latest (failed) experiments:
>>>>
>>>> #lang racket
>>>>
>>>> (require (for-syntax racket/struct-info))
>>>> (require racket/pretty)
>>>>
>>>> (struct foo (a b) #:transparent)
>>>>
>>>> (displayln `("a foo object is transparent: I can see inside: \n  
>>>> (struct->vector (foo 1 2)) ~~> "
>>>>              ,(struct->vector (foo 1 2))))
>>>>
>>>> (displayln `("syntax object is opaque I can't see inside: \n  
>>>> (struct->vector #'foo) ~~> "
>>>>              ,(struct->vector #'foo)))
>>>>
>>>> ;;; Why do two copies of the syntax display? (One copy
>>>> ;;; is a side-effect. The other is a result).
>>>>
>>>> ;;; At expansion time, I can get some graphics in Dr-Racket for
>>>> ;;; definition of foo, but I cannot get likewise 
>>>> ;;; not into the definition of syntax. 
>>>> (begin-for-syntax
>>>>   (displayln 
>>>>    (extract-struct-info
>>>>     (syntax-local-value
>>>>      #'foo))))  ; #'syntax))))
>>>>
>>>> ;;; But the access procedures for #'syntax are known!?!? (I just
>>>> ;;; happen to know that there is a procedure named 'syntax-position';
>>>> ;;; my whole issue is in trying to find out the list of all
>>>> ;;; procedures defined in the system when the syntax type is created!)
>>>>
>>>> (syntax-position #'42)
>>>>
>>>> ;;; Whereas #'foo is known in this module scope,
>>>> ;;; (syntax struct:foo) is not known! Looks like the shorthand
>>>> ;;; #'whatever for making a syntax object is known, but the longhand,
>>>> ;;; presumably (syntax 'whatever), is not known.
>>>>
>>>> (begin-for-syntax
>>>>   (displayln 
>>>>    (extract-struct-info
>>>>     (syntax-local-value
>>>>      #'syntax))))
>>>>
>>>> ~~~~~~~~
>>>>
>>>> Welcome to DrRacket, version 8.2 [cs].
>>>> Language: racket, with debugging; memory limit: 128 MB.
>>>> (.#<syntax:GSI/nanosim-apu-docs/WIKIS/BELEX_3/racket-sandbx-public.rkt:6:8 
>>>> struct:foo> 
>>>> .#<syntax:GSI/nanosim-apu-docs/WIKIS/BELEX_3/racket-sandbx-public.rkt:6:8 
>>>> foo> 
>>>> .#<syntax:GSI/nanosim-apu-docs/WIKIS/BELEX_3/racket-sandbx-public.rkt:6:8 
>>>> foo?> 
>>>> (.#<syntax:GSI/nanosim-apu-docs/WIKIS/BELEX_3/racket-sandbx-public.rkt:6:8 
>>>> foo-b> 
>>>> .#<syntax:GSI/nanosim-apu-docs/WIKIS/BELEX_3/racket-sandbx-public.rkt:6:8 
>>>> foo-a>) (#f #f) #t)
>>>> . . 
>>>> ../../../../../../usr/share/racket/pkgs/errortrace-lib/errortrace/stacktrace.rkt:690:2:
>>>>  
>>>> extract-struct-info: contract violation
>>>>   expected: struct-info?
>>>>   given: #<procedure:...rivate/template.rkt:563:0>
>>>> > 
>>>>
>>>> On Friday, October 29, 2021 at 4:10:37 PM UTC-7 Siddhartha Kasivajhula 
>>>> wrote:
>>>>
>>>>> I was able to find this interface 
>>>>> <https://docs.racket-lang.org/reference/inspectors.html#%28def._%28%28quote._~23~25kernel%29._struct-type-info%29%29>,
>>>>>  
>>>>> but it doesn't quite provide the same information. E.g. (struct-type-info 
>>>>> struct:foo)
>>>>>
>>>>> The ability to "introspect" values in a shell (or in the application) 
>>>>> is useful in languages like python (e.g. dir(object) tells you what 
>>>>> methods it provides, help(anything) gives you the interface/function 
>>>>> signature, docstrings, etc.). I haven't seen this style emphasized in 
>>>>> Racket documentation, and that may be because racket isn't 
>>>>> object-oriented 
>>>>> by default as python is, so that there often isn't a single object 
>>>>> encapsulating all of this information.
>>>>>
>>>>> But all the same, if there are analogous facilities in racket, like 
>>>>> the kind Brian asked about, I'd love to know as well.
>>>>>
>>>>>
>>>>> On Fri, Oct 29, 2021 at 3:14 PM Brian Beckman <[email protected]> 
>>>>> wrote:
>>>>>
>>>>>> Well, as I understand it, a struct (usually? always?), #:transparent 
>>>>>> or not, when declared, defines symbols that are meant to be visible in 
>>>>>> the 
>>>>>> current scope, so (struct foo (a b)) defines foo #|constructor|#, foo? 
>>>>>> #|instance-predicate|# foo-a and foo-b #|data accessors|# , that I can 
>>>>>> call 
>>>>>> on instances:
>>>>>>
>>>>>>     (struct foo (a b))
>>>>>>     (let ([my-foo (foo 42 37)]
>>>>>>        (list (foo? my-foo) 
>>>>>>              (foo-a my-foo) 
>>>>>>              (foo-b my-foo)))  ~~>  '(#t 42 37)
>>>>>>
>>>>>> I would like, given only the symbol foo referring to the struct type 
>>>>>> itself, to discover (at least) the list of procedures foo?, foo-a, 
>>>>>> foo-b, 
>>>>>> plus anything else the author of foo (the type) wants me to see.
>>>>>>     
>>>>>>
>>>>>> On Fri, Oct 29, 2021 at 1:45 PM John Clements <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> In the text below, you refer to the “public” interface. Can I ask 
>>>>>>> what you mean by “public” in this context?
>>>>>>>
>>>>>>> John
>>>>>>>
>>>>>>> > On Oct 29, 2021, at 11:16 AM, Brian Beckman <[email protected]> 
>>>>>>> wrote:
>>>>>>> > 
>>>>>>> > I believe that run time will be the most plausible use case. I may 
>>>>>>> write macros that refer to struct-procedure names at macro-writing 
>>>>>>> time, 
>>>>>>> but I don't expect to invoke the struct procedures at macro-expansion 
>>>>>>> time. 
>>>>>>> My primary issue is "discoverability:" how can I find out the interface 
>>>>>>> of 
>>>>>>> any struct?
>>>>>>> > 
>>>>>>> > On Thursday, October 28, 2021 at 1:00:15 PM UTC-7 
>>>>>>> [email protected] wrote:
>>>>>>> > Are you intending to use the struct procedure names at compile 
>>>>>>> time (such as in a macro) or runtime?
>>>>>>> > 
>>>>>>> > On Tuesday, October 26, 2021 at 5:02:46 PM UTC-7 
>>>>>>> [email protected] wrote:
>>>>>>> > I understand why structs are opaque, by default, but I want to 
>>>>>>> discover the public interface of some struct type, that is, a list of 
>>>>>>> the 
>>>>>>> procedures defined by the struct.
>>>>>>> > 
>>>>>>> > Here is an example. Suppose I want to find out all the procedures 
>>>>>>> defined on an instance of the syntax struct
>>>>>>> > 
>>>>>>> >     #'42
>>>>>>> > 
>>>>>>> > Dr. Racket shows an expander clicky that shows some formatted 
>>>>>>> information inside the instance :
>>>>>>> > 
>>>>>>> > 
>>>>>>> > 
>>>>>>> > Uncapitializing the names in the display reveals the interface:
>>>>>>> > 
>>>>>>> >     (syntax-position #'42) ~~> 790
>>>>>>> >     (syntax-span #'42) ~~> 2
>>>>>>> >     (syntax-original? #'42) ~~> #t
>>>>>>> > 
>>>>>>> > etc.
>>>>>>> > 
>>>>>>> > I want to discover those procedure names in my racket program, not 
>>>>>>> manually by visually inspecting graphics in Dr Racket. 
>>>>>>> > 
>>>>>>> > I found this trick for structs that I define:
>>>>>>> > 
>>>>>>> > #lang racket
>>>>>>> > (require (for-syntax racket/struct-info))
>>>>>>> > (require racket/pretty)
>>>>>>> > 
>>>>>>> > (struct foo (a b))
>>>>>>> > (begin-for-syntax
>>>>>>> >   (displayln 
>>>>>>> >    (extract-struct-info
>>>>>>> >     (syntax-local-value
>>>>>>> >      #'foo))))
>>>>>>> > 
>>>>>>> > ~~>
>>>>>>> > 
>>>>>>> > 
>>>>>>> > 
>>>>>>> > but it doesn't work for the syntax type
>>>>>>> > 
>>>>>>> > (begin-for-syntax
>>>>>>> >   (displayln 
>>>>>>> >    (extract-struct-info
>>>>>>> >     (syntax-local-value
>>>>>>> >      #'syntax))))
>>>>>>> > 
>>>>>>> > ~~>
>>>>>>> > 
>>>>>>> > 
>>>>>>> > 
>>>>>>> > I'd be grateful for advice and an example of how to get the 
>>>>>>> interface of "syntax" without Dr Racket and without grovelling docs.
>>>>>>> > 
>>>>>>> > -- 
>>>>>>> > You received this message because you are subscribed to the Google 
>>>>>>> Groups "Racket Users" group.
>>>>>>> > To unsubscribe from this group and stop receiving emails from it, 
>>>>>>> send an email to [email protected].
>>>>>>> > To view this discussion on the web visit 
>>>>>>> https://groups.google.com/d/msgid/racket-users/8e4ca03e-e276-4c42-a662-4fcf7c994387n%40googlegroups.com
>>>>>>> .
>>>>>>>
>>>>>>> -- 
>>>>>> You received this message because you are subscribed to the Google 
>>>>>> Groups "Racket Users" group.
>>>>>> To unsubscribe from this group and stop receiving emails from it, 
>>>>>> send an email to [email protected].
>>>>>>
>>>>> To view this discussion on the web visit 
>>>>>> https://groups.google.com/d/msgid/racket-users/CAK2VK6tMxFH0oEq4iCgk7PW-4yJTB8xNr_b3F6GPwQS1MZVLwQ%40mail.gmail.com
>>>>>>  
>>>>>> <https://groups.google.com/d/msgid/racket-users/CAK2VK6tMxFH0oEq4iCgk7PW-4yJTB8xNr_b3F6GPwQS1MZVLwQ%40mail.gmail.com?utm_medium=email&utm_source=footer>
>>>>>> .
>>>>>>
>>>>> -- 
>>>> You received this message because you are subscribed to the Google 
>>>> Groups "Racket Users" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send 
>>>> an email to [email protected].
>>>>
>>> To view this discussion on the web visit 
>>>> https://groups.google.com/d/msgid/racket-users/c1c4f0f3-9c8d-430d-8615-4ec2cbea90f4n%40googlegroups.com
>>>>  
>>>> <https://groups.google.com/d/msgid/racket-users/c1c4f0f3-9c8d-430d-8615-4ec2cbea90f4n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Racket Users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected].
>>
> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/racket-users/ad2ae5dd-487a-49b2-84bf-c8315baa5722n%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/racket-users/ad2ae5dd-487a-49b2-84bf-c8315baa5722n%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/523e6d3e-8ad1-44c6-adab-30b73fe073dcn%40googlegroups.com.

Reply via email to