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:

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」
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

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.