r/Compilers • • 1d ago

Patterns

I've been making a programming language for a while now, and just came up with this idea for a feature i'm bout to implement. Patterns.

   pattern P {
    N;
    T(int, int);
    S {
        int x;
        int y;
    };
}
struct MS {
    int x;
}
class C {
    C() {}
    int y;
}
MS fits P(self) {
    N if (self->x == 0);
    T(self->x, -self->x) if (self->x < 10);
    S {
        x: self->x;
        y: 0;
    } if (self->x < 20);
    default N;
}
C fits P(self) {
    default N;
}
int main() {
    C c = C();
    c.y = 0;
    MS ms = {19};
    match (c) {
        P.N => `qout("Worked");
        default => `qout("Failed");
    }
    match (ms) {
        P.S {x, y} => `qout("Worked");
        default => `qout("Failed");
    }
    return 0;
} 

Basically, making user types have the ability to have custom behavior + extraction in match stmts, beyond just enums & integer types

9 Upvotes

9 comments sorted by

3

u/AustinVelonaut 1d ago

Looks interesting! Can you show a practical use case for them that makes pattern matching code simpler / more generic?

3

u/ApprehensivePipe1584 1d ago

Basically, my `match` only matches on integers & enums, so this allows your own non-enum types to interop with `match`, such as a heap wrapper like this
```
pattern Valid {
Valid(void *);
Invalid;
}
class MyHeapWrapper {
private void *data;
bool isValid() {...}
...
}
MyHeapWrapper fits Valid(heap) {
Valid(heap->data) if (heap.isValid());
default Invalid;
}
```
then you could just
```
match (myheap) {
Valid.Valid(data) => ...handle
Valid.Invalid => ...error
}
```
or like, in a game you could have for example
```
pattern Active {
Active;
Idle;
Off;
}
class Player {
...
}
Player fits Active(p) {
Active if (!p.is_dead);
default Off;
}
```
Which not only avoids neding to for example track a PlayerState enum and manually set it, but also allows for easier encapsulation, etc. And also it allows you to make multiple types of the same pattern, like a physics render that has a global pattern for like physics states and can share matching. Also, it's compiel time only and takes up no data, compared to storing enums. Not sure if theres a difference between it and enums except it has more options for tags (sruct tags), it allows you to avoid storing just a random enum in your class (e.g. for cache line purposes), less public fields, and it providing a shared interface automatically instead of manually setting state and providing like a setEnumState method and nonsense.

1

u/Axman6 1d ago

So, algebra is data types which Haskell has had for more than thirty years? it wasn’t the first but has been the influence for their inclusion in many other languages like Rust, Scala. For even more fun, look at pattern synonyms, which are patterns which can abstract applying functions when creating or matching them. 

4

u/ApprehensivePipe1584 1d ago

Oh yeah, its very similar to pattern synonyms in Haskell. Didn't even think of that. I don't think it's the exact same purpose, but definitely similar.

2

u/AustinVelonaut 1d ago

It's not just ADT or pattern synonyms, though. It looks to me more like a form of typeclasses (ad-hoc polymorphism) combined with patterns, where a pattern can have multiple independent concrete instances defined by user data structures.

3

u/Competitive_Ideal866 1d ago

Sounds like active patterns aka view patterns?

2

u/AustinVelonaut 1d ago

Yeah, F# active patterns come closer to describing what the OP proposes, except additionally the constructors are grouped into a typeclass-like pattern which can have multiple ad-hoc fits instances.

1

u/DerekRss 1d ago

Want to see what easy-to-use patterns can REALLY do? Check out SNOBOL4.

1

u/Pie-Lang 1d ago

This is basically adding a customization point to pattern matching. I like it!