effekt-lang / effekt

A language with lexical effect handlers and lightweight effect polymorphism
https://effekt-lang.org
MIT License
334 stars 24 forks source link

`with val` syntax sugar for more complex types #707

Open jiribenes opened 4 days ago

jiribenes commented 4 days ago

Problem statement

There's no way to unpack more complex types the using with val _ = ... syntax sugar.

Motivation

When working with stream, I tried to do something like:

def main() = {
  with val (i, x) = [(1, 'a'), (2, 'b'), (3, 'c')].foreach;
  println(show(i) ++ ": " ++ show(x))
}

in order to unpack the tuple. However, that's wrong since this sugar would imply that foreach takes two arguments as it desugars to something like:

...foreach { (i, x) => ... }

But the correct diet, sugar-free version is the following:

def main() =
  [(1, 'a'), (2, 'b'), (3, 'c')].foreach { case (i, x) => 
    println(show(i) ++ ": " ++ show(x))
  }

Possible and impossible workarounds

I tried to remedy this by using Tuple2(i, x) explicitly, but that reports a parse error:

def main() = {
  with val Tuple2(i, x) = [(1, 'a'), (2, 'b'), (3, 'c')].foreach;
  //             ^ Expected = but got (

  println(show(i) ++ ": " ++ show(x))
}

Similarly if I try to use a custom type:

record Pos(i: Int, x: Char)
def main() = {
  with val Pos(i, x) = [Pos(1, 'a'), Pos(2, 'b'), Pos(3, 'c')].foreach;
  //          ^ Expected = but got (

  println(show(i) ++ ": " ++ show(x))
}

What does work is the following:

def main() = {
  with val tup = [(1, 'a'), (2, 'b'), (3, 'c')].foreach;
  val (i, x) = tup;
  println(show(i) ++ ": " ++ show(x))
}
jiribenes commented 4 days ago

I'm also not 100% sure that we want this feature, but it's very helpful in the zip example in the PR text of #705.

jiribenes commented 3 days ago

Here's the code responsible for parsing with val ...: https://github.com/effekt-lang/effekt/blob/adf76cfd9346072e908e1c49217c4fb32cf57bbe/effekt/shared/src/main/scala/effekt/RecursiveDescent.scala#L198-L204

where as here's the code responsible for parsing val (a, b) = ...: https://github.com/effekt-lang/effekt/blob/adf76cfd9346072e908e1c49217c4fb32cf57bbe/effekt/shared/src/main/scala/effekt/RecursiveDescent.scala#L398-L403