Brad Gilbert saw my Effective Perl post about script runs (a stable feature in v5.32) and offered this Raku version on Twitter:
# Perl 5: /(*script_run:(\d+))/ / \d+ <?{ [eq] $/.Str.uniprops('script') }> /
Bascially, it matches \d+
then immediately uses an assertion that looks that the thing it just matched, $/
, has characters with all the same Unicode properties.
He then defines a new regex
to wrap it all up:
my regex script-run ($r) { $r <?{ [eq] $/.Str.uniprops('script') }> } / <script-run( /\d+/ )> /
That’s fine. The Raku grammars are really cool and amazingly flexible and is a language within the language (well, “slang”).
The thing I find delightful about this Brad’s use of the reduction operator, [...]
with a comparison operator. So, I wrote this little program in Raku (in repl.it):
my $n = 200.rand.Int; if [<] 37, $n, 137 { say "$n is between 37 and 137"; } else { say "$n is not between 37 and 137"; }
This works, and had I thought about it I might have expected it to work. Many (not all) of the math operators don’t care about the order of operations, so 2 + 3 + 5
is (2 + 3) + 5
is 2 + (3 + 5)
. Some operations do care, like exponentiation: 4**3**2
is 4**(3**2)
and is not (4**3)**2
. The reduction operator isn’t what you might expect from most examples; it doesn’t just run the operation with the first two elements and replace them with a single value. It knows what operations to do first.
But, what’s the result of a comparison operator? What does the reduction operator do then?
Raku has “chained” comparisons, but what you write is not what Raku is actually doing (like any good higher-level language):
37 < $n < 137
which is the same as doing each comparison on its own and logically combining the results:
37 < $n and $n < 137
Another way to write this is with the reduction operator:
[<] 37, $n, 137
And it all works out. No loops and short.
One difference: [<] isn't lazy / won't short-circuit:
#!/usr/bin/env raku
sub one { say "ONE"; 1 }
sub ten { say "TEN"; 10 }
# ONE
# False
say so ( one() < 5 and 5 < 3 and 3 < ten() );
# ONE
# TEN
# False
say so ( [<] one(), 5, 3, ten() );