Skip to content
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

Allow indentation and braces (instead of ->) in match clauses #624

Open
osa1 opened this issue Dec 18, 2024 · 2 comments
Open

Allow indentation and braces (instead of ->) in match clauses #624

osa1 opened this issue Dec 18, 2024 · 2 comments

Comments

@osa1
Copy link
Contributor

osa1 commented Dec 18, 2024

Currently handler and match are somewhat similar in that they specify which operator or value constructor they match, and on the right-hand side what to do with them, but the syntax for them are not exactly the same, which looks inconsistent.

Consider:

fun untry_(ex: either<string, a>): <exn_> a
  match ex
    Right(x) -> x
    Left(exn) -> throw_(exn)

val try_ = handler
  return(x) -> Right(x)
  ctl throw_(exn: string) -> Left(exn)

Here both handler and match use ->.

In handler, I can also indent the right-hand side and omit ->:

// also works
val try_ = handler
  return(x)
    Right(x)

  ctl throw_(exn: string)
    Left(exn)

But I can't do the same in match:

// syntax error
fun untry_(ex: either<string, a>): <exn_> a
  match ex
    Right(x)
      x

    Left(exn)
      throw_(exn)

Since indentation is just braces omitted, I can also use braces in handler if I want to define a handler in one line:

// also works
val try_ = handler
  return(x) { Right(x) }
  ctl throw_(exn: string) { Left(exn) }

Which also doesn't work for match.

I suggest we get rid of -> in match and use braces. That would make the syntax consistent with handler, and allow for cleaner match expressions when the right-hand sides are indented.

@TimWhiting
Copy link
Collaborator

Hmm, that's interesting. I didn't know that handlers could use (->).

I think the reason it is needed in match stems from the ability for match patterns to include guards.

For example:

match ex
  Right(x) | x.is-y && x.isnot-z -> println("Here")
  ...

The issue with allowing omitting -> is that any guards would need explicit braces to prevent confusion of guards and bodies. Do you start parsing the rhs as a guard or expression?

match ex
  Right(x) x.is-y && x.isnot-z println("Here")
  ...

One way we could get around this is to move the guard to the rhs of the guard like this

match ex
  Right(x) x.is-y && x.isnot-z | println("Here")
  ...

However for more complex matches where the match pattern is nontrivial you would really like a separator between the pattern and the guard itself - at least to assist parsing without as much lookahead maybe.

match (ex,ex2)
  (Right(x), Right(x2)) x.is-y && x.isnot-z | println("Here")
  ...

I assume the intent of braces is that for 99% of code the braces are optional or assist in readability. If braces where always required even for short match body expressions I personally think it would clutter the matches and reduce readability. For some advanced programmers braces might be preferred, but I don't think they help the learning curve of newer programmers, especially since 1) we have editors that do much better about highlighting & folding regions, and 2) having to learn everywhere you need to put braces before being able to write simple programs is mentally taxing to newer programmers.

@osa1
Copy link
Contributor Author

osa1 commented Dec 19, 2024

I think the reason it is needed in match stems from the ability for match patterns to include guards.

Right, I think with guards there needs to be some separator between the guard expression and the right-hand side of the clause.

I initially though braces could be used as the separator

match ex
  Right(x) | x.is-y && x.isnot-z println("Here") // invalid

match ex
  Right(x) | x.is-y && x.isnot-z { println("Here") } // OK

but the braced expression will be parsed as a trailing lambda in the guard expression.

So maybe we can keep the | and -> in guards but allow braces and indentation without guards. However that will also be somewhat consistent in single line match clauses:

// With guards, we allow an expression after `->`, without indentation or braces
match ex
  Right(x) | x.is-y && x.isnot-z -> println("Here")

// Without guards, the expression need to be wrapped with braces, or indented:
match ex
  Right(x) println("Here") // syntax error

match ex
  Right(x) { println("Here") } // OK

match ex
  Right(x)
    println("Here") // OK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants