mirror of git://git.qorg11.net/kill9.git
Added article about raku
This commit is contained in:
parent
b65b7bbabb
commit
e86d8d173d
|
@ -0,0 +1,168 @@
|
|||
# Raku rocks
|
||||
|
||||
Raku (formerly Perl 6) is a programming language which, despite its
|
||||
former name, it's a very different language from perl. Altough if you
|
||||
already know Perl, learning Raku will be relatively easy.
|
||||
|
||||
Raku introduces (or makes usable) concepts that perl didn't have (or
|
||||
had but were useless and discouraged) in Perl such as Threads,
|
||||
promises, lazy evaluation, and grammars.
|
||||
|
||||
Sigils in Raku make sense unlike in Perl, for example:
|
||||
|
||||
~~~
|
||||
# Perl:
|
||||
my %hash = (key1 => "value", key2 => "value2");
|
||||
$hash{key1} # value;
|
||||
# Raku:
|
||||
my %hash = (key1 => "value", key2 => "value2");
|
||||
%hash{"key1"} # Value
|
||||
~~~
|
||||
|
||||
If a hash is a hash, it is a hash, it won't be converted to a scalar
|
||||
when you want to retrieve data from that hash. Unlike in Perl.
|
||||
|
||||
Raku, unlike perl is a typed programming language, by default all
|
||||
variables you declare are of the type "Any", which means that variable
|
||||
can have any time and can be converted to other type. Nevertheless you
|
||||
can specify which type you want the variable to be:
|
||||
|
||||
~~~
|
||||
my Int $n = 3;
|
||||
my Str $s = "hello world";
|
||||
~~~
|
||||
|
||||
There is a type hierarchy, which means types are based on other
|
||||
types. All types are based on the type `Mu`[fn:1].
|
||||
|
||||
For example, the type `atomicint`, and `bool` derives from the type
|
||||
`Int` which derives from `Cool` which derives from `Any` which derives
|
||||
from `Mu`. All roads lead to Rome and all types lead to `Mu`.
|
||||
|
||||
Raku also has a decent Object Oriented interface:
|
||||
|
||||
~~~
|
||||
Class Socket {
|
||||
has Int $.sockfd;
|
||||
|
||||
method new ($path) {
|
||||
my $mfd = create_socket();
|
||||
connect_socket($mfd,$path);
|
||||
self.bless(sockfd => $mfd);
|
||||
}
|
||||
method send($str) {
|
||||
my $len = $str.chars;
|
||||
write_to_sock(self.sockfd, $str, $len);
|
||||
}
|
||||
}
|
||||
|
||||
my $sock = Socket.new("path/to/socket");
|
||||
$sock.write("hello from raku!");
|
||||
~~~
|
||||
|
||||
Calling C functions from Raku is stupidly easy, to do this only use
|
||||
the [NativeCall](https://docs.raku.org/language/nativecall) module
|
||||
which is included in the standard library, consider the following:
|
||||
|
||||
file.c:
|
||||
~~~
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
print_string(const char *s)
|
||||
{
|
||||
puts(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
~~~
|
||||
|
||||
You have to compile it so it's a shared library:
|
||||
|
||||
`gcc -fpic -shared file.c -o libfile.so`
|
||||
|
||||
file.raku:
|
||||
~~~
|
||||
use NativeCall;
|
||||
|
||||
# Libpath, raku will add the lib and the .so automatically so you don't
|
||||
# have to put libfile.so
|
||||
|
||||
constant LIBPATH = "$*CWD/file";
|
||||
|
||||
# Takes a Str as argument and returns and int32 (which is just an alias to Int)
|
||||
sub print_string(Str --> int32) is native(LIBPATH) { * }
|
||||
|
||||
print_string("C function running in raku");
|
||||
|
||||
~~~
|
||||
|
||||
It will output:
|
||||
|
||||
`C function running in raku`
|
||||
|
||||
Which was expected. Obviously you can import syscalls and any kind of
|
||||
functions you can run in C. Which is useful for doing stuff that is
|
||||
not in the Raku standard library but it's in the C stdlib, such as
|
||||
creating sockets which all the flags you want, or calling `fork()`
|
||||
(which is discouraged as you can use threads and async functions
|
||||
really easily, but if you *really* want to call `fork()` you can call
|
||||
`fork()`.
|
||||
|
||||
## Concurrency in Raku
|
||||
|
||||
Async functions in raku are something very easy. The [language
|
||||
website](https://raku.org) give us this example:
|
||||
|
||||
~~~
|
||||
start { sleep 1.5; print "hi" }
|
||||
await Supply.from-list(<A B C D E F>).throttle: 2, {
|
||||
sleep 0.5;
|
||||
.print
|
||||
}
|
||||
|
||||
# OUTPUT: ABCDhiEF
|
||||
~~~
|
||||
|
||||
the `start` block is called asyncronously, so it sleeps 1.5 seconds
|
||||
and then prints "hi" while the other part prints 2 letters every 0.5
|
||||
seconds. so after printing ABCD, 1.5 seconds have passed, so it will
|
||||
print the "hi" form the `start {}` block.
|
||||
|
||||
Raku also has promises:
|
||||
|
||||
~~~
|
||||
|
||||
sub counter(Int $n) {
|
||||
for 0..$n -> $i {
|
||||
if $i == 21474834 {
|
||||
return "There";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $promise = start {
|
||||
counter(21474834);
|
||||
};
|
||||
|
||||
$promise.then({say .result}); # Will print "There" after finishing.
|
||||
|
||||
say "I'm doing other stuff";
|
||||
say "Blah, blah";
|
||||
sleep(1000); # Simulate stuff-doing
|
||||
~~~
|
||||
|
||||
the `.then` method takes as parameter a block of code, which will be
|
||||
executed after finishing the process. In that code I use `sleep(1000)`
|
||||
to simulate stuff-doing, but if you finished all the stuff you have to
|
||||
do and need the promise to finish, you only do
|
||||
`$promise.result`. Which will wait until it finishes. This is like
|
||||
joining a thread.
|
||||
|
||||
## Rakudo
|
||||
|
||||
Rakudo is the main implementation of the Raku programming language. It
|
||||
compiles Raku code to be run in MoarVM or, if wanted, the JVM[fn:2].
|
||||
|
||||
[fn:1]: Haha discordian reference!
|
||||
[fn:2]: MoarVM is the most used because it's the fastest raku implementation. But you can compile Rakudo to use the JVM if you really want to.
|
Loading…
Reference in New Issue