dark icon indicating copy to clipboard operation
dark copied to clipboard

Add tuple `let` destructuring

Open pbiggar opened this issue 3 years ago • 4 comments

We want to support code like: let (myString, myInt) = ("str", 6), where the user can destructure the tuple into values on the right-hand-side.

This is a prototype of an interaction model for this:

'let ' =>
  let |___ = ___
( =>
  let (|) = ___
myString =>
  let (myString|) = ___
, =>
  let (myString, |___) = ___
'myInt) = ' =>
  let (myString, myInt) = |___
( =>
  let (myString, myInt) = (|)
'"str", ' =>
  let (myString, myInt) = ("str", |___)
5) =>
  let (myString, myInt) = ("str", 5)|

pbiggar avatar Jan 28 '22 04:01 pbiggar

I've been thinking through how this will look, and suspect @pbiggar you've had some ideas around this.

here is the current definition for how let works.

| ELet of id * string * Expr * Expr

The main question I'm thinking through is: should let (a, b) = (1, 2) be powered by the existing Pattern structure, or with a new structure?

A 'new structure' could look like this:

type LetPattern =
  | Simple of string
  | Constructor of ...
  | Tuple of Expr * Expr * List<Expr>
  | ...

...
| ELet of id * LetPattern * Expr * Expr
...

with the current Pattern would be renamed to MatchPattern, and LetPattern.

Looking at prior art, F#'s docs seem to imply that there's only one "Pattern" concept, and splitting "let patterns" from "match patterns" isn't done.

Using the existing Pattern structure as is could look just like:

| ELet of id * Pattern * Expr * Expr

, with existing Dark code migrated (?) to just use a Variable pattern.

Many of F#'s Patterns are non-exhaustive (e.g. a :: b on a list), and these result in compile-time errors there. Ideally, I think, we avoid that, favoring the inability to represent illegal ASTs, but I'm a bit torn - introducing a new concept may be overkill here?

WDYT?

I have a vague intuition that re-using Pattern would be easier technically, but could see that being entirely wrong once the work starts going. So may or may not be a useful metric. I'm leaning towards adding a new type of pattern (LetPattern), so I can start with just a Simple case and expand cleanly from there.

A (bad?) alternative to all of this would be to not worry about other use cases, and define an ELetTuple alongside our ELet.

StachuDotNet avatar Sep 07 '22 14:09 StachuDotNet

I would lean heavily towards the LetPattern idea. Agreed we want to avoid "compile-time" errors, and it seems error prone to have a sort of half pattern (we actually have the same issue with pipes, and it's caused nothing but problems)

pbiggar avatar Sep 07 '22 20:09 pbiggar

Do you agree that a rename of Pattern to MatchPattern is appropriate?

If so,

  • should existing Pattern cases be renamed from PString to MPString?
  • and LetPattern cases then taking the form (let patterns then taking the form LPVariable, LPTuple, etc.)?
  • or maybe this is time to remove our pattern of these prefixes - I believe we've noted that intention elsewhere? One useful thing about the prefix pattern is that finding 'usages of the string pattern' is much easier with PString, over simply using String, so I'm a bit hesitant there.

StachuDotNet avatar Sep 09 '22 18:09 StachuDotNet

Sounds good. I'm happy to keep the prefixes, agreed it's kinda useful.

pbiggar avatar Sep 09 '22 19:09 pbiggar

A more detailed spec is being worked on here: https://docs.google.com/document/d/10mr811ONuUSm6Q1egfv9dGtpN7QdHwhM96uyW8w0140/edit#

StachuDotNet avatar Jan 26 '23 15:01 StachuDotNet

Done

pbiggar avatar Sep 20 '23 00:09 pbiggar