I think the idea that struct
does "full matching" is a misconception. All the patterns for structs allow partial matching:
(struct foo (a b))
(struct bar foo (c d))
(match (bar 1 2 3 4)
[(foo a b) (list a b)])
(match (bar 1 2 3 4)
[(struct foo (a b)) (list a b)])
(match (bar 1 2 3 4)
[(struct* foo ([a a])) (list a)])
All of those patterns succeed. The struct*
one is a bit more partial than the others for ignoring the foo-b
field, but the others still ignore the bar-c
and bar-d
fields.
@AlexKnauth: I don’t want =>
arrows in the middle of key-value pairs. It’s unnecessary, it takes up space, and more space the more entries there are.
That's how I feel about grouping braces. I want grouping when I have a hash where certain entries take up multiple lines, but if they're mostly one-liners, it's unnecessary and distracting. (At this moment I find it more distracting than =>
, even though it does take up one fewer character per entry.)
I have "keywords" =>
and ~?
in there because otherwise there's not much way to prevent ambiguity when the body is a sequence of key
, key value
, key value default
, and key default value
entries. (The last two are awkward to keep unambiguous even in braces.)
@AlexKnauth: I also don’t want …
ellipses involved in the syntax of the rest patterns.
I sympathize with that. I think ellipses have a Rackety feel and might be popular, which is why I went for them there, but I'd love #:rest rest
because Parendown tends to be most helpful when long expressions are precisely at the end of their parents.
I think the same design works with either of these rest syntaxes, neither of them, or both.
@sorawee:
On keys as expressions: I don't think (== pat)
to make "room to have keys that are patterns" would work nicely. If I have:
(define == add1)
(match (hash 1 2 2 3)
[(hash* [(== 1) v]) v])
Is that matching against a pattern 1 or matching against a key value 2?
A key value 2. Since the ==
there isn't free-identifier=?
to the ==
that hash*
would looking for, it would consider this a miscellaneous expression like any other.
I know match
isn't entirely in the habit of parsing things according to free-identifier=?
, but it does in this case.
(Actually, free-identifier=?
doesn't have perfect hygiene itself. If a macro expands into (hash* [k v])
using user input for the k
, I think an occurrence of ==
in that input should not have the meaning hash*
is looking for; the binding site hash*
and the usage site ==
are in separate parts of the code and are engaging in a variable capture that's likely unintended. But every macro that uses free-identifier=?
for keywords has this problem, and trying to solve it in a way that can be easily ported to all those uses of free-identifier=?
across Racket would probably be a digression from this thread.)
@sorawee: a key doesn’t need to be a string/symbol in Racket hash tables
That's why I proposed supporting strings, symbols, keywords, and syntax templates. Just the things that are written in ways that have the least surprising translations to identifiers.
@sorawee: I don’t know what the behavior of (hash* [timestamp])
in your proposal is.
It would be an error because timestamp
isn't quoted or a string.
Not only would allowing it be confusing in all the ways you mentioned, it would also make the parsing of bracketless entries ambiguous because (=>hash 'a => 'artichoke)
could mean the three-entry hash pattern (=>hash ['a] [=>] ['artichoke])
. So I didn't allow it, and I don't want to.
@sorawee: I experimented with the idea of "JavaScript-style identifier-pruning"
Oh yeah, I remember that now, nice!
@sorawee: But what should be the counterpart keyword for partial matching?
Maybe #:extensible
? #:open
?
I want to make sure it's the default though. If people are commonly rejecting hash tables that have entries they don't care about, then there's pretty much no possible change to the JSON that won't break somebody. (Somebody puts their finger on their temple. Oh, it's past me. Yes, past me, everything breaks when you don't prepare for backwards compatibility in advance, but it's nice for it sometimes not to. )
Yesterday I was staunchly in favor of match patterns matching only things that were equal to things the corresponding constructor could return. I was writing that up in my message to this thread. But then I realized I also believe that the better notions of equality are really asymmetrical (partial orders) so as to allow for some backwards-compatible extensions. And since hash entries are one of those extension points that could be backwards compatible, I eventually found myself in favor of partial matching by the time I posted.