I finally finished implementing pattern matching!
I just looked to see when I last updated this blog, and holy crap, it’s been half a year! I tell ya, this had better be one nice feature.
For what it’s worth, I think it is. The pattern matching is recursive, meaning you can break components down as far as you want:
case myWhatever of
Something(List(BlahBlah(5, a), _)) -> ...
That will match if myWhatever
is a Something
whose only argument is a List
whose first element is a BlahBlah
with two arguments, the first being an int 5
and the second being anything, and that thing is now bound to the variable a
.
That took a bit of work, though it only gets me to parity with other pattern matching languages. What’s neat about Haskell is that the remaining type — that is, the next line in the case
list — will take all of that into account. Taking a simpler example, this would fail to compile:
case coinFlips of
List(Heads, List(Tails, _)): ...
List(Heads, List(Tails, _)): ...
_: ...
because the second line is trying to match against a pattern that’s already been matched. And likewise, without that last _ -> ...
line, the statement would fail to compile because some coinFlips
types have not been accounted for (namely, List(Heads, Empty | List(Heads, _) | List(Tails, _)
).
There’s still room for improvements:
- you can’t match against an alias or disjunctive type (ie, you can’t match for
Boolean
, you have to look forTrue
andFalse
separately) - the “remaining type” tends to be pretty exploded out; instead of
List(Heads, Empty | List(Heads, _)
it might sayList(Heads, Empty) | List(Heads, List(Heads, _)
. After a few of these exploded forms chain together, it can get pretty hairy - There’s no tracking of values for what I call “large domain values,” such as ints (as opposed to small domain values, such as
True | False
. For instance, if you match an int against5
, nothing prevents you from matching against5
again. - There’s no mechanism for variable arity destructors, which is why the
List(...)
pattern above had to be desctructed node by node, instead of just asList(Heads, Tails, _)
I may pick off one or two of these soonish, but frankly I’m ready to put pattern matching aside for a bit. It’s taken longer than I’d have liked, and it’s time to move on to some more features.
I think the next thing I’m going to do is exception handling, about which I have some neat ideas. After that, I’m going to fill in the built-in types (which currently only include ints), and for strings I intend to include string interpolation. After that, I’m going to do some I/O work of some sort. And at that point, I think I’ll be ready to start writing some real code in Effes, at lon