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.

  1. A module should add support for better pattern matching.
  2. It could do so with a regular sub, not a Slang or term.
  3. 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!