kellysmith12.21
2020-11-14 11:04:51

Say that I have a syntax class with several cases, and I want to specify that, if a certain attribute does not meet a specific condition, then the class should raise a failure condition. I can include this logic with every mention of the syntax class, but it’s really part of the class itself, and shouldn’t be repeated at use sites. Including the condition checking in every case of the pattern is also not great, since the condition relies only on an attribute that is well-defined for all cases, so is independent of any particular case’s structure.

Since there’s no tidy way to do what I’m trying, I’m wondering if maybe I’m going about things the wrong way?



greg
2020-11-14 13:12:44

Maybe N/A for you. (My pre-first-cup-of-coffee brain was only able to grok, “like a contract for a syntax class”, from what you wrote. Made me think of this, which I’ve seen but not tried.)


mflatt
2020-11-14 13:31:03

That kind of structure within a number seems common. Something similar happens with floating-point numbers, of course, and it turns out that CS hashing does badly there, because it uses the bits of the FP representation as a fixnum.

I’ll run more tests, but so far adjusting the hash function seems like a clear, dramatic win on patterns that seem likely to occur in practice:

https://gist.github.com/mflatt/f55adb5a6d08045c0d6276b4ce64ddfb


mflatt
2020-11-14 14:29:22

It turns out that the bit shuffling should happen at the level of the hash-table implementation, not the hashing function. It’s the hash-table implementation that was ignoring the extra bits, after all. Adjusting at that level is also needed to repair eq?-based tables for fixnums. Meanwhile, performance of immutable hash tables is not affected this way.


ryanc
2020-11-14 14:41:58

One alternative to adding common attributes or checks to every variant of a syntax class is to split it into two syntax classes. The “inner” syntax class has multiple variants, and the “outer” syntax class has a single variant that refers to the inner syntax class and also performs the common checks based on attributes defined by the inner class. The outer syntax class will have to explicitly re-export every inner attribute that you want to use elsewhere. You may find the :stxclass pattern useful: it binds the attributes of stxclass without a dotted prefix.


ryanc
2020-11-14 14:45:53

In OO terms, the solution is to replace “is-a” and implementation inheritance with “has-a” and forwarding.


kellysmith12.21
2020-11-14 16:18:13

@ryanc A wrapper syntax class seems the way to go, especially since the outer class serves as a refinement of the inner class. Thank-you.


kellysmith12.21
2020-11-14 16:20:17

@greg That’s not quite what I was looking for, but that’s a useful utility, nonetheless. Thanks :grinning:


radicalmatt
2020-11-14 17:08:16

@radicalmatt has joined the channel


kellysmith12.21
2020-11-14 17:20:36

Is there a nice workaround for the exception to how ~? works in a datum template? Always succeeding, even with a #f value from a missing binding, is not particularly helpful, when building templates.


alexharsanyi
2020-11-14 22:38:15

Thanks for looking into this and fixing the issue.

I also tried creating my own hash function, which drops the bottom 21 bits (which are the common ones for my data set) and used make-custom-hash , while this was significantly faster, it was still about 3–4 times slower than using an immutable hash. I suspect there is some overhead with using make-custom-hash when compared to the “native” hash implementations.

I was also surprised by the performance of immutable hashes, which I didn’t use until now.


ryanc
2020-11-15 00:46:13

No, because syntax-parse does not distinguish “missing” from “has the value #f”.


hoshom
2020-11-15 07:33:11

Is there any way to make this: #lang racket (struct/contract qty ([n number?])) (struct/contract kg qty ()) (kg "bad") which says qty: contract violation , say kg: contract violation instead?


hoshom
2020-11-15 07:52:00

I suppose can do it by attaching the contract during provide Or rather, automate that by making a defqty macro that makes the struct as well as the provide form.