Skip to content

Add keyword for alternatives in a match construct #579

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

Open
5 tasks
wenkokke opened this issue Feb 24, 2022 · 12 comments
Open
5 tasks

Add keyword for alternatives in a match construct #579

wenkokke opened this issue Feb 24, 2022 · 12 comments
Labels
enhancement New feature or request

Comments

@wenkokke
Copy link

wenkokke commented Feb 24, 2022

edit @pokey:

As discussed in #579 (comment), we'd like to proceed as follows:

Original

There currently is no keyword for selecting alternatives in a match construct. Examples of match constructs are:

  • Python
    match x:
    case Alt1: exp1case AltN: expN
  • Haskell
    f = case x of
      Alt1 -> exp1
      
      AltN -> expN
    or
    f Alt1 = exp1
    
    f AltN = expN

We probably want three keywords:

  • matched to select the value matched on, i.e., x;
  • <ordinal> pattern to select the i’th pattern, i.e., Alt1 to AltN above; and
  • <ordinal> case to select the i’th case, i.e., exp1 to expN above.

Unmodified pattern and case should probably to the scopes relative to the named mark or cursor, i.e., pattern refers to Alt1 if the mark or cursor is in either Alt1 or exp1, and similarly for case.

@pokey
Copy link
Member

pokey commented Feb 24, 2022

Good stuff thanks for filing. A couple thoughts:

  • I'd be tempted to fold "pattern" into "value" and "matched" into "arg", but don't feel super strongly
  • I wouldn't worry about ordinals; those should come for free with Support "every <scope>" / "<ordinal> <scope>" #51 as long as we implement these scope types such that "every" works

@wenkokke
Copy link
Author

Patterns and values are rather different and merging them might let to very confusing selections...

Are you suggesting that "arg" matches the matched value when the cursor is on "match"? There could be arbitrarily nested function calls in x, so having a keyword that jumps directly to the top of the match construct might be extremely useful?

@pokey
Copy link
Member

pokey commented Feb 24, 2022

Let's talk this one out when we discuss the haskell stuff. I like to merge when I can to keep vocabulary down but when it doesn't make sense I'm always happy to add another scope type

@pokey pokey added the enhancement New feature or request label Mar 13, 2022
@pokey pokey mentioned this issue Jun 20, 2022
14 tasks
@purpleP
Copy link
Contributor

purpleP commented Jun 20, 2022

I think it makes more sense to discuss this while we’re working on Rust support as rust pattern matching capabilities and syntax is more complex than that of Haskell. And it’s such an integral part of the language that I don’t see much sense adding rust support without pattern matching support.

@auscompgeek
Copy link
Member

We should probably think about how we can make match arms consistent with case arms. Ref: #247

@purpleP
Copy link
Contributor

purpleP commented Jun 21, 2022

That’s probably a technical limitation, but if it isn’t I would actually allowed each language to define it’s own scopes instead of trying to define a set of common ones and having languages where not all of them are defined. Sure, there’s a lot of commonalities between PLs, but there’s also a lot of differences which would be quite hard to model properly. IMHO it doesn’t even worth trying to do this.

@pokey
Copy link
Member

pokey commented Jun 21, 2022

General philosophy

That’s probably a technical limitation, but if it isn’t I would actually allowed each language to define it’s own scopes instead of trying to define a set of common ones and having languages where not all of them are defined

Yes, today all languages share scope types, and that is in fact a technical limitation that we'd like to remove. Unfortunately, we're dependent on Talon RPC to make that happen, so it's tough to say when exactly we'll be able to move past that limitation

However, even once we are able to have language-specific scope types, consistency is still important. For people who work in multiple languages, consistency is quite helpful. It's one of the nice things about using knausj, for example. You can use roughly the same set of commands to work in many languages. I don't think we need to be dogmatic about consistency, but I'd argue that we should only drop it if we have a good reason to do so.

Match statements themselves

A case for consistency

More concretely, in this case, I would argue that match statements and case statements are conceptually similar enough that we should align the scope types across languages. They have the same elements in all the languages we're talking about here (Python, Typescript, Haskell, and Rust):

  • the variable that is being matched,
  • the different cases,
  • the value expected for each case,
  • the body of the case

In an attempt to reduce cognitive load, I would push for using the same scope types for each of these across languages.

Proposed scope types

I would argue for the following:

  • the variable that is being matched should be called "subject". Alternately, I would be tempted to just not have a scope type for this one at all, as you can just use the hat
  • the different cases should be a new scope type called "branch". We should also support this for branches of an if statement
  • the value expected for each case should be supported as "name", "key", and "condition". Note that in eg Typescript, this would not include the case keyword itself
    • "key" because it looks like the left-hand side of a match,
    • "name" because that's what we use for the left-hand side of assignments, ie even if is a pattern on the left-hand side, so this is kinda similar to that setup.
    • "condition" because it looks like the conditions of an if statement with multiple branches
  • the body of the case should be called "value". We could also support "inside branch", but that should be follow-up work, because today there are no syntactic scope types that support "inside", even though it should be technically quite easy now that Support fully compositional modifiers #672 has merged

In pictures

Following your great example, @purpleP, I've taken some screenshots 😊

"subject" / unsupported

image

"branch"

image

image

"name" / "key" / "condition"

image

"value"

image

image

"inside branch"

image

image

Timeline

And it’s such an integral part of the language that I don’t see much sense adding rust support without pattern matching support.

I think that is fine, as long as we have a fast follow-up PR that introduces it for more languages. I am a bit hesitant to introduce a new scope type that isn't supported by most languages. The follow-up would be a nice first PR for someone fwiw

@wenkokke
Copy link
Author

I think it makes more sense to discuss this while we’re working on Rust support as rust pattern matching capabilities and syntax is more complex than that of Haskell. And it’s such an integral part of the language that I don’t see much sense adding rust support without pattern matching support.

Wait, could you elaborate how Rust’s patterns are more complex? I don’t think I follow.

(I do agree, though, that they’re an essential part of any language which supports them.)

@purpleP
Copy link
Contributor

purpleP commented Jun 21, 2022

I think it makes more sense to discuss this while we’re working on Rust support as rust pattern matching capabilities and syntax is more complex than that of Haskell. And it’s such an integral part of the language that I don’t see much sense adding rust support without pattern matching support.

Wait, could you elaborate how Rust’s patterns are more complex? I don’t think I follow.

(I do agree, though, that they’re an essential part of any language which supports them.)

Unless some extensions were added to GHC or I am missing something Haskell’s pattern matching can only do the opposite of a type constructor, right (aside from primitive types)? It can only match against a type constructors, right?

And in rust they’ve added a few additional ad-hoc features like slice patterns, guard clauses and ability to match on numeric and alphabetical ranges.

@wenkokke
Copy link
Author

Ohh, I didn't know about those! On the Haskell sided, boolean guards, pattern guards, pattern synonyms, record patterns, and view patterns complicate things as well.

However, I think it'd make sense to start by designing for just the basic patterns on algebraic data types.

@purpleP
Copy link
Contributor

purpleP commented Jun 21, 2022

@pokey I like your proposal.

@pokey
Copy link
Member

pokey commented Jun 21, 2022

Ok I've edited my comment above with some new terms after a discussion with @AndreasArvidsson and @phillco. Tl;dr:

  • "case" became "branch"
  • "condition" became "subject" or not supported
  • "name" added synonyms "key" and "condition"

See the updated comment for discussion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants