-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pattern guards #35
base: master
Are you sure you want to change the base?
Pattern guards #35
Conversation
Hi! At a semantic level, this may raise some questions, e.g.: if several successive clauses involve the same expression At a syntactic level, with all due respect, this syntax seems quite ugly and confusing to me. Currently the keyword Another syntactic criticism is that this is an abuse (a new use) of the |
Hi, thanks for the comments. I'll respond to your comments on syntax shortly, but I first wanted to weigh in on the semantic question you raise, namely whether My feeling is that it is least surprising if
It's true that the programmer might want p when e match (
| p1 -> e1
| p2 -> e2
) Indeed, this is one of the main impetuses for that extension of the RFC. For sake of comparison: the compilation of a pattern-matching-related feature in Haskell, view patterns, does involve ensuring that identical expressions that are scrutinized in multiple cases are evaluated only once. But Haskell is pure, so this guarantee is just an optimization in Haskell, whereas it would be semantics-changing in OCaml. (Admittedly, view patterns are a distinct feature from pattern guards, which Haskell also has, but I couldn't easily find how Haskell handles pattern guards in the example you describe). |
I understand this is not directly related to the proposal, but if we are thinking about extending the expressive power of match e with
| ( ({ foo; _ } when foo > 0) | ( { bar = true; _ } when 42 match foo)) -> foo
| _ -> ... (returns the If we go this way, it would also be useful to provide a way to hide a capture variable from a sub-pattern (only used in a local when-clause). Another example: match e with
| ((x, _) when x > 0) | ((_, x) when x > 0) -> x |
Alternative proposalI have also been interested in Lionel Parreaux UCS work, and made a weird proposal that is as expressive as pattern guards in the 2019 blog post Musings on extended pattern-matching syntax, which you could consider including as related (design-only) work. The syntax proposed was as follows: let rec filter_map f li = match li with
| [] -> []
| x :: xs and f x with (
| Some y -> y :: filter_map f xs
| None -> filter_map f xs
) Back in 2019, this syntax was proposed as the composition of two independent features, "with-patterns" and "generalized handlers". I have looked again at this at the end of March this year, and I decided to instead design it as a single, better-behaved construct. I drafted the following grammar:
A slightly more abstract presentation:
Comments on your RFC(P.S.: These comments came out as a little direct. I should clarify that this is a nicely written RFC and I think it is helpful to get a discussion started. On the other hand, it is hard to make progress on syntactic discussions, and I think that it is helpful to get frank feedback early.) I think that syntax designs that encourage people to write the same expression several times are bad. This example from the RFC is bad:
We should design the syntax from the start to discourage this. My proposal for this was basically to reuse Agda's My other comment: I think that the many extensions you propose are not going to help getting support for the RFC; they each have some merit, but they each also give reasons to dislike the proposal and shoot it down. In my experience, in the realm of syntax, "optional extensions/generalizations" do not impress people with your forward thinking, they scare them away. I think that you should focus on one simple syntactic extension proposal, and try to get buy-in for it. |
Note: previous RFC #12 is also relevant prior work. |
Another relevant previous work is the work on pattern guards for Successor ML, see https://github.com/JohnReppy/compiling-pattern-guards . The syntax that they propose is also "bad" in the sense that it encourages guarding on the same expression several times; but in their workshop abstract they detail compilation strategies for pattern guards, and those are easy to extend to other features in this space. |
@alainfrisch : I hadn't considered that, and it's an interesting idea. I believe that implementing this would be a more significant undertaking, as it touches the innards of the pattern match compiler more. In any case, I don't believe the suggestion is at odds with any aspect of the current RFC, so I would move to leave it out of this discussion. @gasche : Thanks for the pointers to those discussions. The It's helpful to know what pieces of this RFC you feel are more or less important. It happens that my preference is the same as yours, I believe. I find what I call "multiway pattern guards" to be a much more important extension than the others mentioned in the RFC, given that they encourage writing an expression once and matching it against different cases. (Indeed, the RFC agrees with you that the bad example you quote is bad — it's the motivation for multiway pattern guards.) I plan on reworking the RFC to highlight "multiway pattern guards" as the main syntactic form and to drop mention of the constructs I feel are less essential — namely, EDIT: In my rework, I plan also to do a better comparison against Haskell/Idris/Agda, as @fpottier suggested. |
One question that is delicate and deserves careful discussion is whether Clearly, if we force sub-clauses to be exhaustive, we are not actually getting much expressivity benefits as this could generally be written as nested matches. But if we don't check exhaustivity, it is easy for people to shoot themselves in the foot by writing a non-exhaustive sub-clause without noticing. I have considered the following options:
It is not obvious which approach is best, maybe (2). |
For me the syntax So, I have meta-question: @ncik-roberts, what is your opinion about active patterns? In which cases your approach is more concise? Do active patterns (in your opinion) have issues except difficulties in efficient compilation? |
I think it'd be better to prefer
The distinctive advantage of |
…e zoo of related constructs
I've pushed a new commit that refocuses the RFC to:
You'll also find some examples of how other languages present similar constructs to the programmer. Of all languages considered, Idris and Agda have constructs that are most similar to the one in the RFC. |
@Kakadu I've read through that RFC and believe it's independent from this one. (Well, they both deal with pattern matching, but I believe the axes are independent.) That's more prominent now with the refocus I just pushed.
My impression is that, even if the language had active patterns, we still might want the feature in this RFC to allow for a partial match on an active pattern to fall through to the outer match. |
Your explanation is decent. Please continue pushing this PR ;) |
This is a proposal for a new syntactic form similar to Haskell's pattern guards. @antalsz and @goldfirere helped prepare this (though mistakes are mine).
A rendered version of the proposal.
Here's an example of the proposed syntax, with carets for emphasis: