Further thoughts on Raku pattern matching
Brains sure are funny things. Or at least mine is; maybe I shouldn't speak for the rest of you.
Last night, I posted a few thoughts on pattern matching in Raku. A bit later, I saw a reply to that post suggesting that it'd be nice to add better pattern matching syntax with a Slang. I responded by saying that it probably wouldn't require a Slang, but that I'm not typically a fan of changing basic syntax purely for convenience (when Raku already gives us so much).
I didn't give the matter much more thought, at least consciously. But my subconscious mind must have been noodling around with the idea because, somehow, I woke up this morning absolutely convinced of three things.
- A module should add support for better pattern matching.
- It could do so with a regular
sub
, not a Slang or term. - Writing that
sub
would be easy.
And, for once at least, that all turned out to be true. Here's the function I came up with:
sub match(*@fns where all .map: * ~~ Code) {
my \topic = callframe(1).my<$_>;
if @fns.first(*.cando: topic.List.Capture) -> &fn {
fn(|topic)
}
}
And here's that function in action:
# before
```raku
for (:add(1, 5), :sub(9, 8), :mul(7, 7)) {
try -> :$add ($a, $b) { say "$a + $b is {$a+$b}" }(|$_)
}
# After
for (:add(1, 5), :sub(9, 8), :mul(7, 7)) {
match -> :$add ($a, $b) { say "$a + $b is {$a+$b}" }
}
And, since match
takes *@fns
as a slurpy, it also lets you do this:
for (:add(1, 5), :sub(9, 8), :mul(7, 7)) {
match -> :$add ($a, $b) { say "$a + $b is {$a+$b}" },
-> :$sub ($a, $b) { say "$a - $b is {$a-$b}" },
-> :$mul ($a, $b) { say "$a × $b is {$a×$b}" } }
I haven't had my coffee yet, but I'm pretty sold on that as a function, at least in my own code. After trying it out a bit (and reflecting a bit on it, post-coffee), I'll probably release that as a module – even though the idea of releasing a 6-line function as a "module" pains me a bit, it seems like something that others could benefit from and an area where standardization wouldn't hurt.
(One change I may make before doing so is to add an error when there's no match, since it'd be easy to add a -> | { }
default case if you want to, and an throwing an error might help surface typos/etc. a lot faster.)
But all of the above was based on waking up with some pretty odd convictions – so please feel free to tell me just how wrong you think I am!