on
Raku 1
After a long break (again) I come back to write about Raku
.
I spent quite some time on Ruby
before moving to Perl
, why ? Because
Perl
is more likely to be installed on a device I get access to, and why not Python
?
Because Perl
has better backward compatibility, I wont need to worry about whether its Python2
or Python3
and which subversion etc.
I heard about Raku before but didn’t really want to give it a try, it is neither as ubiquitous as Perl neither as famous as Python. But last week, I allowed myself to take a look and see how different the language is from Perl and if its worth it for me to spend time learning it and oh well it didn’t disappoint.
Not only Raku is compatible with Perl using Inline::Perl5
, but also:
- has grammar built-in (reminded me of Janet’s PEG)
grammar HTTP {
rule TOP { <method> <path> <version> }
rule method { < GET POST UPDATE DELETE > }
rule path { <-[\s]>+ }
rule version { HTTP '/' 1.1 }
}
say HTTP.parse('GET /foo/bar.html HTTP/1.1');
# 「GET /foo/bar.html HTTP/1.1」
# method => 「GET 」
# path => 「/foo/bar.html 」
# version => 「HTTP/1.1」
- has type and type restriction
subset Even of Int where * %% 2;
sub addEven (Even $x, Even $y --> Even) {
$x + $y
}
for <2 4 3 5> -> $x, $y { say try addEven $x, $y }
# 6
# Nil
- subroutine dispatch
- quite nice cli argument parsing built-in
- built-in parallelism, asynchronicity and concurrency
0.1 + 0.2 - 0.3
actually evaluate to0
- built-in profiling
- …and a lot more !
A very nice example coming from here, is how to start from a base and add more and more feature.
sub fib($n) {
given $n {
when 0 { 0 }
when 1 { 1 }
default { fib($n-1) + fib($n-2) }
}
}
say fib 30;
say now - INIT now;
# 832040
# 3.572343194
Now if we want to add “security” with types, only allowing number, non negative etc.
sub fib(UInt $n --> UInt) {
given $n {
when 0 { 0 }
when 1 { 1 }
default { fib($n-1) + fib($n-2) }
}
}
say fib 30;
say now - INIT now;
# 832040
# 4.632358196
Now if we use native
type instead of Raku
type (raw C type if I got it correctly), we can gain some performance.
sub fib(uint $n --> uint) {
given $n {
when 0 { 0 }
when 1 { 1 }
default { fib($n-1) + fib($n-2) }
}
}
say fib 30;
say now - INIT now;
# 832040
# 3.450367755
Now using a currently experimental caching feature, we can gain more performance.
use experimental :cached;
sub fib(uint $n --> uint) is cached {
given $n {
when 0 { 0 }
when 1 { 1 }
default { fib($n-1) + fib($n-2) }
}
}
say fib 30;
say now - INIT now;
# 832040
# 0.001929062
So now we have a code that is type safe (type error would happen at comptime and not runtime) and that is much faster than the first draft code.
Just in case, the is cached
will cache the previous return value from function, and since with the fib function we reuse a lot of previous calls it helps a lot !
There are tons of ‘magik’, you can easily define your own operator as well
sub infix:<@@>(Str $a, Str $b) {
say "doing something";
$a ~ $b
}
my $s = "foo" @@ "bar";
say $s;
# doing something
# foobar
Some more magic
say [+] <1 2 3 4 5>;
say <a b c> Z <1 2 3>;
say <a b> X <A B C>;
say <a b c d e f> Zxx <1 0 0 0 1 1>;
# 15
# ((a 1) (b 2) (c 3))
# ((a A) (a B) (a C) (b A) (b B) (b C))
# ((a) () () () (e) (f))
And this is just scratching the surface, I am very excited about this language.