Raku Programming Language

A powerful, feature-rich, multi-paradigm programming language

Download Get Involved

Why Raku?

say 'Hello World';
# Multiple dispatch
multi sub fib (0 --> 0) {}
multi sub fib (1 --> 1) {}
multi sub fib (\n where * > 1) {
    fib(n - 1) + fib(n - 2)
}
say fib 10;
# OUTPUT: 55

# Roles and classes
role Shape {
    method area { ... }

    method print_area {
        say "Area of {self.^name} is {self.area}.";
    }
}

class Rectangle does Shape {
    has $.width is required;
    has $.height is required;

    method area {
        $!width * $!height
    }
}

Rectangle.new(width => 5, height => 7).print_area;
# OUTPUT: Area of Rectangle is 35.
# Inifinite and lazy list
my @fib = 0, 1, * + * ... ;
say @fib[^11];
# OUTPUT: (0 1 1 2 3 5 8 13 21 34 55)

# Feed operator
@fib[^20] ==> grep(&is-prime) ==> say();
# OUTPUT: (2 3 5 13 89 233 1597)

# Function composition
my &reverse_primes = &reverse  &grep.assuming(&is-prime);
say reverse_primes ^20;
# OUTPUT: (19 17 13 11 7 5 3 2)

my @a = 1..4;
my @b = 'a'..'d';
# Zip two lists using Z meta operator
say @a Z @b;
# OUTPUT: ((1 a) (2 b) (3 c) (4 d))
say @a Z=> @b;
# OUTPUT: (1 => a 2 => b 3 => c 4 => d)

# Hyper Operators
say @b «~» @a;
# OUTPUT: [a1 b2 c3 d4]

# Junctions
say 'Find all the words starting with a lowercase vowel'.words.grep: *.starts-with: any <a e i o u>;
# OUTPUT: (all a)
grammar INIParser {
    token TOP { <block> <section>* }
    token section { <header> <block> }
    token header { '[' ~ ']' \w+ \n+ }
    token block { [<pair> | <comment>]* }
    rule pair { <key> '=' <value> }
    token comment { ';' \N* \n+ }
    token key { \w+ }
    token value { <-[\n ;]>+ }
}

my $match = INIParser.parse: q:to/END/;
; Comment
key1=value1
key2 = value2

; Section 1
[section1]
key3=value3
END


say $match<block><pair>[0]<value>;
# OUTPUT: 「value1」

say $match<section>[0]<block><pair>[0]<value>;
# OUTPUT: 「value3」
# Promise
my $promise = start {
    my $i = 0;
    for 1 .. 10 {
        $i += $_
    }
    $i
}
my $result = await $promise;
say $result;
# OUTPUT: 55

# Concurrency
react {
    my $current-proc;
    whenever $script.watch.unique(:as(*.path), :expires(1)) {
        .kill with $current-proc;
        $current-proc = Proc::Async.new($*EXECUTABLE, $script);
        my $done = $current-proc.start;
        whenever $done {
            $current-proc = Nil;
        }
    }
}

my $modules-load = start @files
    .grep(/ \.(yaml|yml) $/)
    .sort(-*.s)
    .race(batch => 1, degree => 6)
    .map(-> $file {
            my $yaml = self!load-yaml($file, $schema, $problems);
            with $yaml {
                Easii::Model::Module.new(parsed => $yaml, source => $file.basename)
            }
     })
    .eager;

# Supply
my $bread-supplier = Supplier.new;
my $vegetable-supplier = Supplier.new;

my $supply = supply {
    whenever $bread-supplier.Supply {
        emit("We've got bread: " ~ $_);
    };
    whenever $vegetable-supplier.Supply {
        emit("We've got a vegetable: " ~ $_);
    };
}
$supply.tap(-> $v { say "$v" });

$vegetable-supplier.emit("Radish");
# OUTPUT: «We've got a vegetable: Radish␤» 
$bread-supplier.emit("Thick sliced");
# OUTPUT: «We've got bread: Thick sliced␤» 
$vegetable-supplier.emit("Lettuce");
# OUTPUT: «We've got a vegetable: Lettuce␤» 
say '🦋'.chars;
# OUTPUT: 1
say '🦋'.codes;
# OUTPUT: 1
say '🦋'.encode.bytes;
# OUTPUT: 4

my $raku = 'راکو';
say $raku.chars;
# OUTPUT: 4
say $raku.uninames;
# OUTPUT: (ARABIC LETTER REH ARABIC LETTER ALEF ARABIC LETTER KEHEH ARABIC LETTER WAW)
say $raku.comb;
# OUTPUT: (ر ا ک و)
say +$raku.comb;
# OUTPUT: 4
subsetof Int where * > 0;

sub f (ℕ $a,$b --> Array of ℕ) {
    Array[].new: $a², $b²;
}

say f 1,2;
# OUTPUT: [1 4]

# Native Types
my int @a = ^10_000_000;
say [+] @a;
# OUTPUT: 49999995000000
sub MAIN(
    Str   $file where *.IO.f = 'file.dat',  #= an existing file to frobnicate 
    Int  :size(:$length) = 24,              #= length/size needed for frobnication 
    Bool :$verbose,                         #= required verbosity 
) {
    say $length if $length.defined;
    say $file   if $file.defined;
    say 'Verbosity ', ($verbose ?? 'on' !! 'off');
}

# $ script-name
# Usage:
# script-name [--size|--length=<Int>] [--verbose] [<file>]
   
#    [<file>]                 an existing file to frobnicate
#    --size|--length=<Int>    length/size needed for frobnication
#    --verbose                required verbosity

# $ raku frobnicate.raku --verbose
# 24
# file.dat
# Verbosity on

# Another example with multi MAIN
multi MAIN ('install', Str $something, Bool :$force) {
    say "Installing $something {'by force' if $force}";
}

multi MAIN ('run', Str $something) {
    say "Running $something";
}

# $ script-name
# Usage:
# script-name [--force] install <something>
# script-name run <something>

# $ script-name --force install raku
# Installing raku by force
# Using NativeCall to access libnotify and show a notification
use NativeCall;

sub notify_init (str $appname --> int32) is native('notify') { * }
sub notify_uninit is native('notify') { * }
class NotifyNotification is repr('CPointer') { * }
sub notify_notification_new (str $summary, str $body, str $icon --> NotifyNotification) is native('notify') { * }
sub notify_notification_show (NotifyNotification) is native('notify') { * }

if notify_init 'MyApp' {
    notify_notification_show notify_notification_new 'My Notification', 'Notification Body', Str;
    notify_uninit;
}

# Using Inline::Python to access python and its libraries
use Inline::Python;
my $py = Inline::Python.new();
$py.run('print "hello world"');
# OUTPUT: hello world

# Or
say EVAL('1+3', :lang<Python>);
# OUTPUT: 4

use string:from<Python>;
say string::capwords('foo bar');
# OUTPUT: Foo Bar
=begin pod

=head1 Documenting code in C<Raku>

=item L<Raku docs|https://docs.raku.org>

=end pod

=begin pod

=head1 Red

Take a look at our Documentation: L<https://fco.github.io/Red/>

=head2 Red - A **WiP** ORM for Raku

=head2 INSTALL
Install with (you need **rakudo 2018.12-94-g495ac7c00** or **newer**):

=begin code :lang<bash>
zef install Red
=end code

=head2 SYNOPSIS

=begin code :lang<raku>
use Red:api<2>;
model Person {...}
model Post is rw {
    has Int         $.id        is serial;
    has Int         $!author-id is referencing{ Person.id };
    has Str         $.title     is column{ :unique };
    has Str         $.body      is column;
    has Person      $.author    is relationship{ .author-id };
    has Bool        $.deleted   is column = False;
    has DateTime    $.created   is column .= now;
    has Set         $.tags      is column{
        :type<string>,
        :deflate{ .keys.join: "," },
        :inflate{ set(.split: ",") }
    } = set();
    method delete { $!deleted = True; self.^save }
}
model Person is rw {
    has Int  $.id            is serial;
    has Str  $.name          is column;
    has Post @.posts         is relationship{ .author-id };
    method active-posts { @!posts.grep: not *.deleted }
}
my $*RED-DB = database "SQLite";
Person.^create-table;
=end code

=begin code :lang<sql>
-- Equivalent to the following query:
CREATE TABLE person(
    id integer NOT NULL primary key
    AUTOINCREMENT,
    name varchar(255) NOT NULL
)
=end code

=begin code :lang<raku>
Post.^create-table;
=end code

=begin code :lang<sql>
-- Equivalent to the following query:
CREATE TABLE post(
    id integer NOT NULL primary key AUTOINCREMENT,
    author_id integer NULL references person(id),
    title varchar(255) NOT NULL,
    body varchar(255) NOT NULL,
    deleted integer NOT NULL,
    created varchar(32) NOT NULL,
    tags varchar(255) NOT NULL,
    UNIQUE (title)
)
=end code

=begin code :lang<raku>
my Post $post1 = Post.^load: :42id;
=end code

=begin code :lang<sql>
-- Equivalent to the following query:
SELECT
    post.id,
    post.author_id as "author-id",
    post.title,
    post.body,
    post.deleted,
    post.created,
    post.tags
FROM
    post
WHERE
    post.id = 42
=end code

=end pod
use v6.c;
# TODO: Add operator, slang, macro examples
say Date.today.year;
# Output: 2020
say Date.today.later(:2years).year;
# Output: 2022

# TODO: Add more examples
sub add (Int $a, Int $b) {
    $a + $b
}

add 'string';
# ===SORRY!=== Error while compiling error.raku
# Calling add(Str) will never work with declared signature (Int $a, Int $b)
# at file.raku:5
# ------> <BOL>⏏add 'string';

Resources

Try Online

Coming from another programming language?

If you are coming from another programming language, these documentations may be of help to you:
Python, JavaScript, Ruby, Haskell, Perl

If you want to use other programming languages and their libraries inside Raku, you can use Inline::* modules, such as:
Inline::Python, Inline::Perl, Inline::Go, Inline::Ruby, Inline::Lua