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.

