quasarbright / PongChamp

Other
1 stars 1 forks source link

Algebraic data types and pattern matching #12

Open quasarbright opened 3 years ago

quasarbright commented 3 years ago

We're already planning on adding objects and arrays, but we also want union types. Tuples would be cool too. You get union types for free in a dynamically typed language because it's like everything is a union over all types. But if we add static typing, it'll be nice to have discriminated unions. Or if we want to be really cool, we could do non-discriminated unions like type script. But that'd be hard. Structural subtyping would be cool too, but that's a topic for another issue

At any rate, We should make pattern matching constructs like const {x,y} = pointObj in js and tuple unpacking (x,y) = pair if we do tuples. It could all be syntactic sugar. But we should allow for nested stuff like const {x,y as {z, p as (a,b)}} = {x:1,y:{z:2,p:(3,4)}}

We've been meaning to make a desugaring pass anyway, since we're doing inline desugaring in the interpreter for stuff like let x = 2; -> let x; x = 2;. Having a dedicated pass and two AST types would make future passes much easier to implement

quasarbright commented 3 years ago

Simplest form of json-like pattern matching I can think of is (x,y,z,...) for tuple/list patterns, x for simple var pattern that'll match anything, literal patterns like 1, "hello", true, etc., and {"x": x, "person": {"age": age, "name": name}} with sugar like {x, "person": {age, name}}. The former is necessary for matching against objects with complex keys like {"mike's name": mike_name} which cannot be written as a variable name.

this stuff could simply desugar to accesses and declarations, but then you'd get key-errors instead of pattern match fails. Additionally, you'll want a construct for multiple cases for union (discriminated or otherwise) data. Especially for object patterns. Steal from python:

let mode;
case obj:
  match {"mode": mode_}:
    mode = mode_
  match _:
    mode = "default"

Need to alter syntax obviously, but that's the idea.

Inline matches like {x,y,z} = obj could desugar to cases where there's a _ match at the end which throws a pattern match failure or something

This'll make #10 harder. But you could just consider any fallible pattern (patterns that can fail. Any pattern other than x or _ patterns) match as a non-definite initialization.

Also, I think matches should declare variables, not try assign them if they exist. So keep that in mind for scoping

quasarbright commented 3 years ago

NOTE: This is going to deviate us from js syntax

quasarbright commented 3 years ago

in js, you can do

const {x, ...rest} = obj

which binds x to obj.x and rest to obj without the x field.

That would be cool