I must apologies for what follows will be more of a rambling than an 
exercise in clear thinking. That is because I am a bit stuck and thought 
I'd seek help.

I have been thinking some about languages and how it isn't always easy to 
clearly separate language being implemented from the language used to 
implement it. The picture gets particularly blurry in Lisps. This time 
around the question that gave me pause was one of implementing symbols. 
Better still Racket keywords, since like many lispy terms "symbol" has so 
many confusing meanings that its nigh impossible to tell what people mean 
exactly. I specifically talk about autoquoted datums. Two interned symbols 
that are equal? are eq?, two keywords that are equal? are eq?, 42 is eq? to 
42, etc. Symbols are bad example cause people often think about 'symbol or 
identifier with semantics being: perform variable lookup.

Someone on this list said everything in Racket is a struct, so lets start 
there.
 
 (struct kw (symbol))

We can also come up with some syntactic representation and extend our 
language with read and read-syntax that translate this new syntax into 
kw-struct as needed. But then we also demand that two syntactically equal 
kws end up being the same value in the language, so no matter where our 
reader encounters #kw(foo) it must produce the same value. This must be 
true across module boundaries, too. Just like Racket keywords. So, what are 
we to do? There's time when the reader runs, followed by expansion. Does 
this mean they need to communicate somehow? Also, the reader "runs", that 
is it is written in Racket (or some derivative) after all, but reader's 
environment isn't one where expansion happens, and that of the final code 
being evaled is different still. Right? 

To ensure eq? of two kws with the same printed representation we'll 
probably want to keep some global table around that keeps track of 
"interned" kws. So, for any two #kw(foo), our reader would have to produce 
something like (lookup-intern-kw  #:symbol 'foo), which at run-time would 
consult the table of kws and return the (kw 'foo) already there, or create 
a fresh entry and return that new struct. Two observations: (a) it follows 
that the global table is one that must exist at runtime - not while the 
reader runs, and (b) we end up relying on the host language for symbol 
equality after all 'foo is eq? 'foo and that allows us to key the table by 
symbols e.g. 'foo.

Is this how you would do it? Is there a better way that involves the reader 
more and relies on the runtime less?

Bonus question. What if we allow families of kws effectively partitioning 
kws into namespaces: #kw(family name). This appears a small variation of 
the above, where you'd simply assemble a compound symbol from family and 
name to use for the table lookup. That is until you allow parameterizing by 
"current-family", so kw declaration can omit the family part and it gets 
inserted as needed - not unreasonable in a language with modules or 
explicit namespaces. We could allow something like this:

#lang racket/kws
#:current-family addams

#kw(morticia)

now any kw within a module without family must translate into one of addams 
family. But also any #kw(addams morticia) in a different module must be eq? 
to the one above and in fact to any one like that anywhere. One exception 
is probably if we send them across Racket spaces which IIUC amount to 
running separate VMs. In the above example the reader would have to be 
aware of #:current-family declaration that may appear at the top of the 
module. We'd probably translate that to some (current-family 'addams) 
parameter setup, or wrap #%module-begin body in parameterize, then every kw 
without explicit family would have to check the (current-family) parameter. 

Is there a way to push this more to the read-time? If there is, what 
happens if we load the module and enter REPL? Could we ensure its reader is 
properly parameterized that it would use appropriate current-family?

How screwed up is my thinking here? Is there a way to leverage the reader 
more and rely on the runtime less? I imagine that'd make kws discussed 
lighter weight? We talk about phases some in Racket, but reader runs 
somewhere or rather sometime, too. I'd like to have a clearer picture in my 
head, I guess.

Thanks

-- 
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