Time to actually design it.
https://gleam.run/news/v0.33-exhaustive-gleam/ has some good resources.
https://compiler.club/compiling-pattern-matching/ has decent implementation stuff.
In terms of actual design, so far I'm fine basically co-opting Rust's semantics without any major innovations or design changes. Captures and conditions are important but not particularly common, at least in Rust code, so I kinda dislike its
Foo(x, y) @ x
style but don't have a pressing need to even implement it, let alone try to improve it.match foo with | Thing { a, b, _ } -> thing1 | Other { .x = x, .y = y } -> thing2 // syntactic sugar for the above? | Other2 { x, y } -> thing3 | _ -> default end
The
.x =...
syntax instead ofx: ...
might make distinguishing variable captures vs. matching on variables easier, ponder it more later.Questions:
if let
?while let
? I'm going to assume that everylet
is a pattern match 'cause that's nice; are we going to bother with pattern matching in function args? Eh, probably but it's not critical so far, we'll see how hard it is.
https://perso.ens-lyon.fr/thais.baudon/icfp2023.pdf has some good references on compiling pattern matching. https://dl.acm.org/doi/10.1145/1411304.1411311 seems to be the most recent. PDF of it available here: https://www.cs.tufts.edu/~nr/cs257/archive/luc-maranget/jun08.pdf
From https://lobste.rs/s/rnqlef/named_arguments_rust_if_you_want_them:
I wish that you could just put .. at the end of a strict definition to extend from default. I think it would be some nice syntax sugar that makes a common case much less noisy.
let x = Target { bar: 3, .. Default::default() }; // becomes let x = Target { bar: 3, .. };
Also to consider: Haskell/Erlang-y style pattern matching on function signatures, allowing you to define a function as a pattern match. For example, Rust does not let you do this:
fn bar(None: Option<i32>) -> i32 { panic!() } fn bar(Some(x): Option<i32>) -> i32 { x }It just complains that the match isn't exhaustive and that
bar()
is redefined. But really it's just sugar for a function containing amatch
. If you could write it in Garnet, maybe it would look like this?fn bar(None Option[I32]) I32 = panic!() or bar(Some(x) Option[I32]) I32 = x end
One nuisance I have with this in Erlang is that it then makes it a bit tricky to actually hunt down the implementation of
bar()
that you happen to be looking for at any particular time. Usingor
instead offn
, in the style of OCaml'slet ... and ...
, is an attempt to at least force people to keep the implementations together. Another alternative is a lint to warn you if the implementations are far apart or too long; if it's more than a screenful of code then it's easy to miss the second impl or theor
further down.This is pure sugar, but it is pretty nice sometimes.
https://dl.acm.org/doi/10.1145/3689746
Interesting paper on pattern matching constructs and syntax.
FTR - regarding the paper, one point that is easy to overlook when skimming, is the proposed syntax for languages not using "significant whitespace" for blocks (pg. 6):
if x { > 0 then "positive"; == 0 then "null"; else "?" }