@lexi.lambda The short answer is that identifier-binding doesn’t implicitly switch to “macro result” view in the same way that syntax-local-bind-syntaxes or syntax-local-value does. If you make the macro return x*, then you get an out-of-context error in either variant of your example. Equivalently, (identifier-binding (syntax-local-introduce x*)) produces 'lexical and both cases. Overall, the intent is that x* as a result of the macro should be bound. To achieve that goal, syntax-local-bind-syntaxes includes an implicit syntax-local-introduce on its argument, as does syntax-local-value and other syntax-local-... functions. The identifier-binding function does not include an implicit syntax-local-introduce. That’s why you get #f in the first example; the binding has macro-introduction marks, but the identifier passed to identifier-binding does not. In the second example, you’re effectively canceling the macro-introduction mark for the binding (by using syntax-local-introduce to make the identifier look like it came from the macro use), and then looking up a binding from an identifier with more scopes still finds the binding. To make a long story short, use syntax-local-introduce on the argument to identifier-binding if you want to see a bindings that as it will visible in the example, and its kindof an accident that you get 'lexical in your second example. The documentation should be made more clear which operations implicitly switch to macro-result view (with an implicit syntax-local-introduce) and which ones don’t.
@mflatt Thank you for that explanation. I admit that I find it pretty difficult and confusing to remember all the subtle differences between different syntax functions and how they adjust scopes. Is that what the syntax-local- prefix actually means? Functions that include an implicit syntax-local-introduce?
I don’t think it’s as simple as having a syntax-local- prefix. I expected to sort this out better with the expander rewrite, but it was too easy to just do whatever the current functions do without thinking about it more.
Okay. The actual problem I was trying to solve when I ran into this is that I was binding some identifiers into a definition context, then calling local-expand on some syntax using the context, and the identifiers in the resulting syntax were not free-identifier=? to the identifiers I had.
Adding the syntax-local-introduce before binding the identifiers fixed the issue, but I’ll try moving it to someplace after the binding and see if that still works, since that seems closer to the right thing to do based on your explanation.
Switched cat from radius to width/height, and added an option to not inset when the whiskers are wider than the face.
I want to make a gui interface now, where I can fiddle with all the parameters to standard-cat and see what it looks like real time.
basically I want to play with the ear positioning, arc length, and extents, and then the whisker length and droop.
it’s not rackety until it has 20 optional keyword arguments
@lexi.lambda Is there any chance the identifiers that were not free-identifier=? to your binders were accessed from a syntax property set within the local expansion but accessed outside? Local-expand in effect does a syntax-local-introduce on its argument and return. Ran into this issue with turnstile with my own conversion to definition contexts there. Need to syntax-local-introduce when adding the property and when accessing the property.
Yep, I thought about that, and that was my theory. Normally I wouldn’t need to do that sort of low-level mucking about with identifiers, but I had to do that because type variables are represented as identifiers, and I needed to do some type substitution.
The trouble is that it goes in as a syntax object to be expanded and comes out as a property.
Also, hello @michael.ballantyne, I didn’t realize you were in slack. :wave:
So did you solve your problem, or is there still a difficulty?
(@lexi.lambda)
Question
I got it working by adding a syntax-local-introduce in the right spot. So far it seems to work fine.
Question for everyone: is it expected behavior that racket will use compiled files for dependencies built by raco make even when the source file has been modified since? If so, why? Seems like it would be friendlier to check the timestamps transitive dependencies like raco make does, but I guess I could see that being too expensive.
@michael.ballantyne No, that’s not the expected behavior, and racket shouldn’t be doing that
or, perhaps to be more clear, if a.rkt depends on b.rkt and both have zo files, and then you modify b.rkt, then the zo for a.rkt will still be used since a.rkt is not newer than the zo file
but if you modify b.rkt and then run a.rkt, it will not use the zo file for b.rkt
@mflatt (or maybe someone else) I’d like to provide an argument to resolve-module-path-index that produces a module path with the same semantics as calling dynamic-require on the MPI directly
I got somewhere with (resolved-module-path-name (current-module-declare-name)) but that doesn’t work when running raco make
@samth I don’t understand the question. Can you provide a more complete example?
@mflatt Currently, I have this function:
(define (do-requires [ns (current-namespace)])
(parameterize ([current-namespace ns])
(for ([m (in-list to-require)]
#:when m)
(dynamic-require (module-path-index-join '(submod "." #%type-decl) m)
#f))))I want to write a similar function, but which generates a list of (require ...) syntax objects
I’ve written this: (define (get-requires)
(for/list ([m (in-list to-require)]
#:when m)
;; FIXME: is this really the right code?
#`(require (only-in (submod #,(resolve-module-path-index
m
(resolved-module-path-name
(current-module-declare-name)))
#%type-decl)))))
which works when the code that uses it is run with racket, but not with raco make or raco expand
the elements of the list to-require are generated by (variable-reference->module-path-index (#%variable-reference)) in other modules
I’m trying to arrange for the submodules of a Typed Racket module that declare types or contracts to have requires for the same submodules in the modules that the outer module depends on
My first thought is (variable-reference->module-path-index (#%variable-reference)) in place of (resolved-module-path-name (current-module-declare-name)), but I’m not sure that’s the right idea.
Won’t that point to the inside of the Typed Racket implementation, where that function is?
I though you were trying to do something like that. If you want to be relative to the context where the require appears, I’m not following well enough to see why "." doesn’t work.
Well, maybe I see…
If I have modules a.rkt and b.rkt, where b requires a, then in the #%type-decl submodule of b I want to generate a require for the #%type-decl submodule of a
and the MPI in the code (named m) points to a
Is the issue that m in get-requires might be a submodule path, so you can’t just wrap it with submod?
I tried just putting m directly in the submod form but apparently require can’t take a module-path-index (which is what m is) directly
certainly (submod #,m #%type-decl) would be the nicest thing to be able to write there
I’m not clear on where m came from that it’s a module path index, but then it seems like (module-path-join '(submod "." #%type-decl) m) would be what you want.
Do you mean module-path-index-join?
Yes
m comes from a call to (variable-reference->module-path-index (#%variable-reference)) in the other module (a in my example)
That produces a similar error to one I had earlier: ?: bad syntax for require sub-form
in: #<module-path-index:((submod "." #%type-decl) "x.rkt")>
However, that was enough to get me to this:
(define (get-requires)
(for/list ([m (in-list to-require)]
#:when m)
;; FIXME: is this really the right code?
#`(require (only-in #,(cons 'submod (resolved-module-path-name (module-path-index-resolve (module-path-index-join '(submod "." #%type-decl) m))))))))which I think will make unportable zo files but should be enough to allow me to make progress on this
Thanks!
I agree that’s not the right thing. How about (collapse-module-path-index (module-path-index-join '(submod "." #%type-decl) m))?
That seems to work!
@michael.ballantyne See the custom-load package. It provides a compiled-load handler that implements recursive timestamp checking.