
Fun fact: the name of a gensym symbol on Chez is not generated until it is needed. What Racket on Chez does - I don’t know.

There’s no guarantee. In the current implementation, the names will be different when they’re generated in the same place and run of Racket, independent of namespace.

@philip.mcgrath Out of curiosty, why compile example/common
explicitly instead of just compiling example/foo
(which will recompile whatever example/foo
uses)?

Anyone with numerics expertise and an opinion on https://github.com/racket/racket/pull/2565 ? It looks plausible to me…


@notjack which frustrating things are you thinking of?

Thanks, I suspected that might be the case. For context, I’m trying to figure out how to generate values at phase 1 that will be embedded in expanded phase 0 code and will be unique at runtime (but they only need to be unique within a single module). I see a few ways to do this. I could arrange for runtime definitions to be generated that hold gensyms and reference those definitions instead of generating quoted values directly. That would require some extra bookkeeping to ensure the definitions end up in the right place, though. Another might be to use identifiers instead of symbols, made with generate-temporary and preserved with quote-syntax instead of quote, then compared at runtime with free-identifier=?. That seems heavyweight, since I care about the equality check being fast, but maybe it doesn’t matter. A third way would be to just hold a mutable counter in memory at compile time and generate unique symbols by appending the counter to the end and incrementing the counter atomically using box-cas!, and I think this would guarantee that each symbol would at least be unique from other symbols generated that way during the compilation of a single module, which is all I need. Is there a better option?

@mflatt not an expert on numerics but i took a look at the paper and the code and they seem to agree. I executed the tests he posted on pasterack and accuracy is higher without the issues at z=18.25 so looks good to me. only thing i would say is that i would prefer to avoid (z . < . X) comparisons in the codebase, but that’s really just a syntactic niggle.

I’ve got a question for you friends: https://stackoverflow.com/questions/55380849/is-it-possible-to-change-the-result-of-a-syntax-class

@mflatt should add that a few runs of his tests showed the solution to be slower by 13.6%.

Wonder if there’s anything that can be done to improve that while still having the same benefits he presented in his method.

@soegaard2 racket-on-chez doesn’t use chez gensyms

No, something like .result
or .norm
, .value
, or some other named attribute, is necessary. You can make that attribute a short name, like a single letter… that’s what (expr/c contract)
does with its .c
attribute.

That last option sounds right. The macro expander does that to generate “unreadable” symbols to represent distinct bindings. A counter that resets with each module expansion has the benefit of generating a consistent result when the same module is recompiled.

Okay, I’ll go with that, then. Thanks!

Come to think about it, you could name the attribute the “empty symbol” \|\|
, and then instead of p.result
you could use p.
… (define-splicing-syntax-class pair
[pattern {~seq a b} #:attr \|\| #'(list a b)])
(syntax-parse #'(hash 1 "do" 2 "re" 3 "mi" 4 "fa" 5 "sol")
[(_ p:pair ...) #'(list p. ...)])

Wow, tricky :stuck_out_tongue:

My issue is that I’m generating those macros, so I don’t know in advance if the element is gonna be a splicing class or not. To prevent that, I made a dummy class that has a result
with it’s own content, and I apply this class to everything. This way, I always have a .result
attribute. But I was trying to find a better way.

I’m curious what the macros look like when you use them, and what they’re meant to do

I made a way to declare objects that have attributes, like so: (define-quest-actor fish
(attributes
(position vec?)
(color symbol?)))
To create an instance of this fish, you would do like this: (fish (position (vec 1.0 1.0))
(color 'red))
But some contracts, like vec?
, trigger a different syntax, in which you can omit the (vec)
call: (fish (position 1.0 1.0)
(color 'red))
Since I don’t know in advance if the attribute is going to have such a contract, I need to generate a macro that handle having some attributes splicing, and some not.

The implementation is there: https://github.com/euhmeuh/rilouworld/blob/master/private/bundle/expander.rkt

I hope it makes sense, cause this macro is starting to get out of control x)

Thanks!

Interesting… Why doesn’t it?

I think because it wouldn’t behave the way current racket does, but @mflatt may know for sure

(currently racketcs gensyms are about 3x slower than Racket gensyms and much much slower than Chez gensyms when you don’t look at them)

Ah, looks like this explains why:
https://github.com/racket/racket/commit/fd462604bd653544b7e3898d2a67d8fc4fea8e48

Yes, to “because it wouldn’t behave the way current racket does”. I have been tempted to add Racket gensyms (which are more conventional) to Chez Scheme and vice versa, but the difference has never been big enough to finish either addition.

It would be interesting to measure how many Racket gensyms are forced in the chez sense

Does the vec?
predicate have the syntax class associated with it or something?

@samth I wish I didn’t have to leave racket and use the terminal for so many things. I’d prefer to write a program in a #lang
saying how I’d like to compile and test code. I have memory problems so command line APIs and shell scripts are generally very frustrating for me.

ah, so more racket functions for performing compilation/package tasks?

I see you’re embedding <own-attr>.parse-pat
and <own-attr>.parse-res
as syntax objects into the define-syntax
struct. I would avoid this, and instead define a syntax class to express this.
Then instead of putting those syntax objects in the define-syntax
struct, I would put identifiers that point to those syntax classes.

This is similar to what you’re already doing with #'any-exp
, #'vec-exp
, etc, so I would just do that more, for new macro-defined syntax classes in addition to pre-defined syntax classes.

Yes. And more determinism / reproducibility, and more APIs like that whereis
module proposed by Ryan.

I think it would also be interesting to know how many uses of Racket gensyms in macros are unnecessary.

which things are non-deterministic?

Racket macros generally do not/should not use gensym
, because it enforces uniqueness by virtue of being uninterned, but uninterned symbols become interned symbols when they are written to bytecode. Rather, Racket macros that need unique identifiers should use generate-temporary
, instead, which enforces uniqueness by adding a fresh scope, which is a kind of uniqueness that cooperates well with the macro system.

Things seem pretty deterministic on the same machine. Cross-machine determinism is what I had in mind.

Yes. That best practice really needs to be explicitly documented somewhere. Ideally with a link to it in the docs for gensym
.

Hey @alexknauth just an FYI, your hygenic reader macro package doesn’t work if:

- You bind something not in a reader macro.

“not”?

Ya, basically if you bind something with a standard macro.

and then 2. try to reference that thing from a macro generated by a reader macro.

Like, as an example. Imagine I’ve made a (admittedly silly) macro (define-foo)

the semantics of (define-foo)
is to expand to (define foo 42)
, where foo
is added to the user’s scope.

Next, you create a reader macro, say #my-super-awesome-macro
, which reads to (#%awesome)
.

The (#%awesome)
macro expands to foo
, where foo
is whatever foo
is bound in the user’s scope.

If I then write the following program:

#lang my-reader-macro racket
(define-foo)
#my-super-awesome-macro
You’ll get a foo
unbound error.

So #%awesome
is an unhygienic macro, but the reference to it should be generated hygienically?

(But if you just do: (define-foo)
foo
it obviously works fine.)

Yes, ,that is correct.

I want #my-super-awesome-macro
to always be read as this specific (#%awesome)
form.

I assume that if you write (define-foo)
(#%awesome)
That works?

Yes it does.

Because in that case (#%awesome)
has the outer scope, not the inner one.

Unfortunately this might be a fundamental issue, as I can’t find any way to work around it without just dropping hygenic reader macros. :disappointed:

which things?

I think you should always get the same zo files, for example

How is #%awesome
defined? Does it use datum->syntax
, or does it use syntax-local-introduce
or something?

I don’t really know if there’s any specific problems. I just don’t feel like I understand the big picture of how all the different flags, config files, parameters, and environment variables can affect compilation. I also don’t know how I’d test and verify aspects of the compiler.

It’s likely much more of a communication and documentation hurdle than a technical one.

@leif I got some version of this to work in the most useless way. By fiddling with the definitions of define-foo
and #%awesome
, I was able to get this program to work: (define-foo)
#my-super-awesome-macro
;=> 42
However, putting anything around the use of the reader macro causes it to fail: (define-foo)
(add1 #my-super-awesome-macro)
;=error> foo: unbound identifier in: foo

Sorry. my brain feels like it went through a juicer, so I had to step away from my computer for a bit. reading now.

@alexknauth #%awesome
uses datum->syntax.

Anyway, #%awesome
was defined with something like this:

(define-elaborate this
(define/syntax-parse foo (datum->syntax this-syntax 'foo))
#'foo))

Where define-elaborate
expands to a define-syntax
. (A la the example @lexi.lambda was helping with yesterday.)

err…define-syntax
and syntax-parse
.

Is that the elaborator for the editors?

Anyway, If I change the definition of define-foo
to use syntax-local-identifier-as-binding
and syntax-local-introduce
and the definition of #%awesome
to use syntax-local-introduce
, then I get it to work if #my-super-awesome-macro
is exactly at the top level, but not within a definition or function call.

Actually, this program fails the same way: (define-simple-macro (define-it)
#:with x (syntax-local-identifier-as-binding (syntax-local-introduce #'it))
(define x 42))
(define-syntax-parser refer-to-it
[(_) (syntax-local-introduce #'it)])
in another file: (define-it)
(add1 (refer-to-it))
;=error> it: unbound identifier in: it

But (define-it)
(refer-to-it)
;=> 42
works fine.

@alexknauth ya, that’s the elaborator for the editors.

Okay. Although that seems like an odd way to bind a new variable.

(I know @michael.ballantyne complains all the time about people needing to use syntax-local-introduce
for that purpose.)

@leif for which purpose exactly? (curious)

Oh, IIRC, its just that (ideally) syntax-local-introduce
should just be an internal implementation detail rather than part of the public API. I forget why though. Anyway, I’m sure Michael would know more about what Michael thinks. :wink:

huh :thinking_face:

Umm… I think its related to the fact that it exposes that inside of a macro is more of a negative space, while outside is a positive space. Which causes @lexi.lambda to make her…uhh….macro-like-apply?

Anyway, sorry, I’m probably not being very coherent right now. I also don’t really understand the argument entirely myself.

sounds like someone somewhere ought to write a blog post

syntax-local-introduce
is just get-the-current-scope
+ apply-a-scope
so it seems like removing it would really mean “don’t expose scopes to macro programmers”

I was thinking it meant that there shouldn’t be an introduction scope that’s added to macros by default, and instead evaluating #'(foo ...)
should create a scope and add it to things. If anyone remembers that racket-users thread started by lexi that talked about alternate approaches to hygiene, that’s what I’m thinking of.

@notjack that’s an idea proposed previously by Andre van Tonder

yes! that’s the one

I think you want SRFI 72

I think I don’t know what I want

I mean, SRFI 72 is his spec document

I think I want to know what I think I want…I think?

What I mean is although that’s definitely the right spec for that alternative, I don’t know how I feel about that specific alternative.

But ya, I think @samth is right, that its having scope sets as part of the public API…probably.

Scope sets don’t feel like they are part of the public API now

they’re sort of indirectly referred to via introducer functions

but there’s no scope?
predicate or scope-set?
predicate

the relevant thread is syntax/parse is not hygenic
from March 2018

@notjack I think the docs for make-syntax-introducer
make it clear that scopes are part of the API

it has a bad name for historical reasons

and it’s encapsulated by a procedure rather than a struct with a procedure that takes it as an argument

@samth I don’t think encapsulating scopes in procedures is the same as making scopes part of the API. The functionality is the same, but it feels totally different to users.

@notjack Is that true? Most of the users I’ve talked to (or been in the past) either have no idea what syntax-local-introduce does, or understands that its basically a toggle switch for a macro scope.

If there was a scope?
function that answered #true
to the results of make-syntax-introducer
would you feel differently?

@leif In fairness, I guess I can’t say if it feels totally different to users. But it does feel totally different to me.

fair.

@samth Yes, provided there were also a few scope-related functions whose names started with scope-
. Like (scope-add scope? syntax?)
, and similar for scope-remove
/ scope-flip
.

Anyway, there’s also the syntax-binding-set
and family.

(admittedly Mathew made that public because of some really terrible macros I needed to write.)

this package is closer in spirit to what I think of as a “public scopes API”: https://docs.racket-lang.org/scope-operations/index.html

Right but that library is a very simple wrapper over the current API

Yup. But it feels totally different and is much more intuitive to me.

And even more, the concepts and operations in that library are 1–1 with the racket API

So I can totally agree that such an API would be nicer

But I think they expose the same things

Just with nicer names. :wink:

(for some definition of ‘nicer’ anyway.)

Anyway, from my (very limited) experience, the more complex the macros you make, the more scope sets pop out of the API. But at least most of the time I don’t have to think about it (too much)

probably.

@samth Think about it this way: what if everywhere racket currently uses numbers, it instead described “successor introducers” which were functions that you had to call with special arguments in order to do math? Like (num1 'add num2)

The functionality is the same. But it’s a vastly different experience.

@notjack Wait, aren’t there some FP languages that do exactly that? And the ‘successor introducers’ do feel like just numbers.

?

Like,where 3 is a function.

And + takes a function that takes two functions and results in another function that is the sum?

@leif There are languages that do that for a semi-internal representation of things but they usually have reader-level syntax to support it and go to efforts to simplify / hide this representation in things like error messages. Because it confuses the hell out of people.

If you want to write a number like three, you just write the number 3
. If you want to add things, you just write 3 + 5
. This might be achieved through a representation of numbers as closures and defining +
as a closure-accepting-and-returning operator. But you aren’t forced to actually think about that.

And docs don’t describe numbers as “successor introducers”, they just call them numbers.

@mflatt I guess because I thought that didn’t work. I’m not sure exactly what I was doing when I formed that belief (much less a way to reproduce it), because I’ve been doing it this way for a while, but there are points in my workflow when I run into linkage errors, and I thought compiling only example/foo
wasn’t enough to solve them if example/common
had changed.

One possibility is that I’m conflating in my memory pressing Run
in DrRacket, which I do frequently (I think I have ⌘i
+ ⌘s
+ ⌘r
in muscle memory), with explicitly running raco setup
. I vaguely remember there being some issues where the two interacting caused friction.

@notjack Okay, then I must be missing something here. Because I don’t see how your description of (num1 'add num2)
is substantively different from num1 + num2
. But that’s okay. Brain no longer feels like jelly thank god, so I can get back to work. :slightly_smiling_face:

@leif There’s no functionality difference. There’s only communication and experience differences. For example, when I put the text cursor over +
in DrRacket and press F1, I get taken to documentation for +
.

People underestimate how much those kinds of differences affect what code people write

OH! You are literally just talking about documentation, not about API design itself.

Okay, in that case yes, that makes sense.

In that case, its hard to say for macros, because there isn’t any good guide in the docs (from my experience), and therefore its pieced together by academic papers, books, and blog-posts.

That, and poking others…

So…. null?

lol slack fail. Srry.

Still works :p

Totally uninformed random question. Is there anything Jekyll-like in Racket? I know I could hack Scribble but I’m looking for something a bit closer to what Jekyll does in Ruby. My guess is that it could be done much more naturally in Racket via macros.

@krismicinski I think you want frog

yeah, was just looking at toad
too :slightly_smiling_face: https://parametri.city/blog/2015-06-01-toad-design.html

Thanks for the frog
pointer. I’ll check them out.

Yeah, this looks really nice. I’ll try moving my site over from Jekyll soon!

Last few days, I’ve been exploring redoing my own blog, using a Makefile
driving a few command-line tools, which are mostly a few pieces copied/modified from Frog.

I might put those pieces in a lib called “tadpole”. :slightly_smiling_face:

Or I might just make one or two missing Racket packages (e.g. to make Atom and RSS feeds).

also jekyll is no longer the hotness in static blog generation

and just share the other glue code in a repo, not a package.

everything should be a package!

I don’t plan to abandon Frog. I’m just kind of at the point where, if anyone wants it to do more features or be more configurable, I don’t think I can really do that.

@samth what is the hottest now?

I kind of feel like there’s some Greenspun’s Tenth Rule about static blog generators being implementations of make.

I hear about hugo

github pages supports jekyll out of the box. But it doesn’t work with the bibtex2html
tool I use, so I hand-compile and then upload to generate my site.

I tried using hakyll
a while back. It was nice. Then the API changed from Arrows to Monads and broke 50% of the entire codebase I wrote up laboriously while learning Haskell along the way.

I’d like to start using Racket-based tools as a matter of principle, though.. :slightly_smiling_face:


You’re right, it does sound good, and I’ve used it once. My intuition tells me that frog
is going to take slightly less work to make it do what I want, but I think frog
is built on top of Pollen.

Pollen and Frog are different enough that I wouldn’t say one is built on top of the other, but if I must, I would say that Pollen is built on top of Frog. In fact, Pollen’s Markdown mode simply uses Frog’s Markdown parser. Pollen’s syntax highlighting is also borrowed from Frog.

You are right that Frog is going to take less work to make it do basic stuff. Pollen’s main goal is not static blog generation, so it doesn’t have, for example, basic page layout supports.

IMO, deciding whether Frog or Pollen is the right choice depends on how much you want to have control over document manipulation. Frog won’t let you manipulate content much (in a nice way), whereas in Pollen, the intermediate document data structure is xexpr of which you have a complete control.

@greg at Racketfest lots of people talked about racket-mode for Emacs — kudos for working on it!

@sorawee in general I do want pretty low-level control over how HTML and such gets laid out.

I’m all for building beautiful things, but often when I’m hacking on websites I just need to do something kind of dirty because the time investment often isn’t worth justifying (why I use Jekyll, tbh). That being said, I’d be willing to put in some time to learning a tool if it were in Racket (more than I would in Ruby)

@krismicinski @samth I use Hugo for my website, it’s very powerful but with a bit of a learning curve. I have now gotten to the point where I have my templates the way I want, and I can produce the Hugo markup for my website from a big org-mode file, so I barely even see it. Netlify automatically then builds and hosts the website itself. Works nicely :slightly_smiling_face:

@krismicinski you get a lot of low-level control with Hugo, if that’s what you want. I think there might even be a semi-automated Jekyll-to-Hugo converter out there.

Hugo is in Go though, so you need to learn and get used to the go templating engine, which is kind of weird, but you get used to it.

Yeah, I use Jekyll very productively now and know how to hack on it well, but I’d be interested in using something Racket-based for catharsis..