
@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 require
s 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.