Instead of a new `#%q-expression` form, I think there's potential to use 
`#%datum` or `quote` itself for this. Potentially, the only thing that 
makes numbers (for instance) special is that the reader, printer, IDE, and 
bytecode systems already know what module(s) the number structure type(s) 
come from. As long as user-defined structure types are able to provide each 
of those systems with the same knowledge (e.g. through a structure type 
property), then they can have the same benefits.

One complication: User-defined structure types typically aren't 
interoperable across phases and module registries, the way kernel-defined, 
cross-phase persistent structure types like numbers and lists are. Even if 
we know what their module path is, that's not all the information needed, 
some of the information only "exists" once a generative `struct` definition 
has created it.

In particular, I think using `quote` on user-defined types brings up 
cross-phase difficulties: A `quote` expression is typically computed at 
phase (N + 1) for use as a constant at phase N. If we expect to be able to 
compute it at compile time using phase-(N + 1) instances of user-defined 
structure types, and if we expect to be able to process it at run time 
using phase-N instances of those types, then the `quote` operation itself 
needs to perform some kind of marshalling between those.

How to do that marshalling? Well, whatever materials we need, the structure 
type property can provide them. For instance, certain structure types might 
go through no change at all (e.g. simple procedures, perhaps). Certain 
others may do their marshalling using a (module path, identifier, data) 
intermediate stage just like Matthew Flatt and Alexis King are talking 
about. Maybe some values would even use complex higher-order marshalling 
behaviors (similar to contracts or an FFI), letting us take an object that 
uses phase-(N + 1) tools internally and wrap it up in such a way that it 
can process phase-N input and output values. And maybe some steps of the 
marshalling would use side effects, for instance to implement the interning 
zeRusski is talking about.

Whatever the technique we use for marshalling any particular structure 
type, once the marshalling has completed at phase N, we're often going to 
want a value that's compatible with the phase-N instance of the structure 
type. And that means that by the time we ever see that result value, the 
structure type must have been defined at phase N already -- which means the 
module where the `quote` appears should (at least indirectly) have a 
phase-N dependency on the module that contains that definition.

To make this work, this time it can be the structure type itself that 
"carries its own `require` at all times" (via the structure type property), 
and a `quote` implicitly acts as a `require` for all the structure types 
that appear inside it. This has a lot in common with the `#q` approach, but 
it seamlessly blends in user-defined types with core types: We can say that 
when we `quote` numbers and lists, we implicitly `require` their modules 
too, but that since those modules are part of the kernel, the `require` has 
just been imperceptible the whole time.

For types that need to be marshalled to bytecode or saved as plain text 
from a graphical editor, I agree that the (module path, identifier, data) 
format seems like a fine choice.

That said, I do want to point out that in this approach, the *bytecode* and 
*plain text* uses of (module path, identifier, data) triples would be 
subtly different from each other. In bytecode, the module path would be 
required at phase 0 (because, as far as I understand it, phase 0 is all 
that there is in the bytecode) and the construction would be performed near 
the start of the module. In plain text Racket code, that phase 0 behavior 
only happens as the *result* of compiling a `quote` form. Since `quote` 
marshals the value down one phase, it must have started out at phase 1, and 
thus we need the reader to return a phase-1 instantiation of the value.

This suggests that although we would use a reader syntax like 
`#q(module-path identifier data)` in this approach, its behavior would be 
to `require` that module path at phase 1 and perform the construction 
immediately.


On Tuesday, April 23, 2019 at 12:45:04 PM UTC-7, zeRusski wrote:
>
> (begin-for-syntax
>   (list 1 #k(foo) 2))
> ;; => ; tag: undefined;
>
> This can be solved with (require (for-syntax prelude/tags)) but as with 
> other autoquoted types I'd probably want to be able to just write them in 
> any phase. Docs say some stuff about namespaces having a scope that crosses 
> all phases plus separate scopes for each phase. Is there a way for a 
> binding to span all phases without cooperation from the user?
>

I think one thing that might help is to have #k(foo) read as:

(
  (let ()
    (local-require (only-in prelude/tags tag))
    tag)
  'foo)

This still supposes that `#%app`, `let`, `local-require`, and `only-in` are 
bound, so each module might need to require `racket/base` at the 
appropriate phase levels for each `#k` it uses.

I think with the particular `#q` approach Matthew Flatt was talking about, 
the situation would be pretty much the same, but the error message would 
specifically report that no `#%q-expression` transformer was bound. And the 
approach I'm talking about would be similar, reporting that `#%datum` was 
unbound.

Since most code will need stuff like `#%app` to be bound anyway, in many 
cases all the necessary bindings will already exist, and there won't be any 
additional step to take.



> Another problem is with REPL. Above runs fine when I run the module, but 
> not if I type in REPL. 
>

I think for testing out reader macros at the REPL, you can at least use 
(current-readtable 
...) to set the readtable to a different one to use in subsequent commands.

I don't have any experience yet with using custom `#lang` languages at the 
REPL, so maybe there's an easier option. I hope someone else chimes in.

-Nia

-- 
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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to