@sorawee It’s worth noting that define-syntaxes
can only show up in fully-expanded code at the module top level—define-syntax
used as an internal definition is guaranteed to go away after expansion. And that makes sense, when considered together with the things others have already pointed out.
Hey, I got a somewhat complicated question for syntax experts around here. I’m trying to attach meta-information to a syntax identifier at compile-time, by overriding the identifier defined by struct with my own (and keeping the old identifier somewhere for future reference). But once an identifier has been defined with define-syntax
, it seems impossible to override it (I get an “already defined” error). Is there a better way to embed more info into a struct identifier at compile-time?
I’m doing all this because I need struct’s field names (and parent’s field names recursively), and they are not provided by extract-struct-info
(only the final getters and setters)
I’d like to do something similar to what struct does: creating a struct:id
and keeping it inside a syntax variable so that other structs can use it when inheriting. But as the identifier for my struct is already taken, I can’t use the exact same name.
Does all that make sense?
@jerome.martin.dev usually doing this requires that there’s a struct-type-property you can use like prop:match-expander
. I think there’s a similar property for structs
I think prop:struct-info
is what you want
but aren’t struct properties used at run-time?
maybe I could just… use make-struct-type
and keep my own wrapper around that, or something… my head hurts
I have some questions. Do you want to attach the meta-information to existing structs defined by other libraries, or would you be fine with a macro that defines new structs with meta-information attached?
the later :slightly_smiling_face:
Okay that makes it slightly easier I think.
You shouldn’t need to go all the way down to make-struct-type
.
What I’ve done in the past is define the struct with different id passed in for the #:name
and #:constructor-name
fields, and then use define-syntax
with an instance of a compile-time normal+struct-info+extra-meta-information
struct, which has prop:procedure
for the normal behavior, prop:struct-info
for the struct-info behavior, and prop:whatever-you-need-for-meta-information
for your meta information.
I see
by "normal+struct-info+extra-meta-information
struct" you mean a struct instance that exists only at compile-time?
or a syntax?
Like this: (begin
(struct foo [field ...] option ...
#:name internal-foo #:constructor-name internal-foo)
(define-syntax foo
(normal+struct-info+extra-meta-information
(make-var-like-transformer #'internal-foo)
(extract-struct-info (syntax-local-value #'internal-foo))
...extra-meta-information...)))
Where somewhere you have a struct definition for normal+struct-info+extra-meta-information
in a begin-for-syntax: (begin-for-syntax
(struct normal+struct-info+extra-meta-information [normal struct-info extra-meta-information]
#:property prop:procedure (struct-field-index normal)
#:property prop:struct-info (lambda (self) (normal+struct-info+extra-meta-information-struct-info self))
#:property prop:extra-meta-information ...stuff...))
I think I’m starting to understand, I just don’t get why you would need a prop:procedure though
Oh, that’s so that you can still use the struct name as a constructor, like you can use (foo 1 2 3)
to make an instance of (struct foo [a b c])
ok I see! In my case, I made the macro that generates the struct to also generate a syntax used as the constructor, so I guess I won’t need this
I’ll try your method, thanks!
@jerome.martin.dev in answer to your earlier question, prop:struct-info
is meant to be used at compile time, not runtime. So you’d use (define-syntax foo (make-my-meta-info))
where my-meta-info
is a struct type with prop:struct-info
.
And then your macros can use syntax-local-value
to get the my-meta-info
instance and use it to decide what code to generate
Ok, that’s what seemed the most logical, but I wasn’t sure I understood it correctly!
(oops I didn’t notice that that’s exactly what alex’s code does - long codeblocks are very hard to read on mobile)
it seems like it’s nearly working! Thanks a lot for your help!
so, brainfart here, I’m trying to call (system* "/usr/bin/ls" "/tmp/") from inside a serve/servlet, everything works outside the servlet, but always fails inside … I’m guessing this is because of sandbox but I can’t find the docs for it
is there a way to get a call to system* to work inside a servlet?
wow, so this is a new one
apparently trying to run emacs with /dev/null as the working directory was the problem
I guess this is why we have a /var/run/ folder
@renyiyuan has joined the channel
Just want to make sure I understand its implication correctly. This means that suppose I want to perform some optimization (let’s say, constant folding) on fully expanded code and module mod1
has a macro foo
with content (+ 1 1)
:
- If I change
(current-compile)
, I can skip performing optimization insidedefine-syntax
because other modules (saymod2
) that usefoo
frommod1
would expandfoo
to(+ 1 1)
anyway, so it will be optimized regardless. - If I trigger the optimization per module (by overriding
#%module-begin
), then I have both options. That is, if I perform optimization insidedefine-syntax
, then any usage offoo
will directly result in2
. In contrast, if I don’t, then(+ 1 1)
will still exist, and won’t be optimized.
Do I understand correctly?