Raku By Example
View me onGitHub
## Subroutines
##------------

# Declaration done with the keyword `sub`.

sub shout-greeting { "HELLO!!!" }

say shout-greeting; # HELLO!!!

# The last expression of sub is returned implicitly although it can be done
# explicitly with the keyword `return`. Also a colon is not necessary after
# the last expression in a sub.

sub greeting { return "Hello!" }

say greeting; # Hello!

## Parameters of a subroutine
##---------------------------

# Positional parameters - these are parameters whose meaning is defined by their
# position. Positional parameters are required by default but they can be made
# optional by using a default value OR appending them with a `?`.

sub fullname_v1($fname, $lname) {
    return $fname ~ " " ~ $lname;
}

# say fullname_v1();             # Error
say fullname_v1('Joe', 'Sae');   # 'Joe Sae'

sub fullname_v2($fname = 'John', $lname = 'Doe') {  # parameters made optional
    return $fname ~ " " ~ $lname;                   # with default values
}

say fullname_v2();               # 'John Doe'
say fullname_v2('Jonas', 'Eda'); # 'Jonas Eda'

sub fullname_v3($fname?, $lname?) {  # parameters made optional with `?`
    return $fname ~ " " ~ $lname
    if $fname.defined and $lname.defined;
}

say fullname_v3();                # ' '
say fullname_v3('Ada', 'Ula');    # 'Ada Ula'

# Named parameters - these are parameters whose meaning is defined by their names.
# They're created by prepending `:` to their name. They're optional by default
# but can be made required by appending them with `!`.

sub fullname_v4(:$name, :$surname) {
    return $name ~ " " ~ $surname;
}

say fullname_v4(name => 'Mugen', surname => 'Eta'); # 'Mugen Eta'
say fullname_v4();                                  # ' '

sub fullname_v5(:$name = 'Jane', :$surname = 'Doe') {
    return $name ~ " " ~ $surname;
}

say fullname_v5(name => 'Fuu', surname => 'Ichi');  # 'Fuu Ichi'
say fullname_v5();                                  # 'Jane Doe'

sub fullname_v6(:$name!, :$surname!) { # parameters made required with `!`
    return $name ~ " " ~ $surname;
}

# say fullname_v6();                                  # Error
say fullname_v6(name => 'Jinn', surname => 'Ngan'); # 'Jin Ngan'


## Type constraints
##-----------------

# Typed parameters - The parameters list of a sub can be typed. Besides
# specifying a type, a type constraint can be made stricter by specifying if 
# only defined values are accepted (by using `:D`) or only undefined values 
# (by using `:U`) for a certain type.  

sub multiply(Int $a, Int $b) { $a * $b }

say multiply(5, 3);         # 8
#say multiply('one', 'two'); # Error

sub substract(Int:D $a, Int:D $b) { # accept only defined Ints
    $a - $b
}

substract(10, 15); # -5

sub only-undef-str(Str:U $arg) { # accept only undefined Strs, namely Str
    say $arg
}

say only-undef-str(Str); # Str
say only-undef-str('a'); # Error

# Return type - The return type of a subroutine can be specified by using `-->`
# followed by the type right after the parameters list. Although there are
# other ways of achieving the same thing, this method is the most ubiquitous.

sub add2($a, $b --> Int) { # only allowed to return an Int
    $a + $b
}

say add2(9, 3);     # 12
say add2(1.1, 2.0); # Error

## Parameter traits
##-----------------

## Multiple dispatch
## -----------------

# Subroutines can share the same name but have different signatures. This is 
# achieved by prepending each sub declaration with `multi`.

multi sub add(Int $a, Int $b) { $a + $b; }

multi sub add(Str $a, Str $b) { $a ~ $b; }

say add(1, 2);      # 3
say add('a', 'b');  # ab

# When `multi` is used, `sub` can be omitted:

multi fact(0 --> 1) { }
multi fact(Int $n --> Int) {
    return $n * fact($n-1)
}

say fact(3); # 6

## Anonymous subroutines
##----------------------

# A nameless or anonymous, as they call it, is created by storing a `sub`
# with its parameters list and body in a variable.

my $add = sub (Int:D $x, Int:D $y) { $x + $y }

say $add(10, 15); # 25

# An anonymous sub can also be created using a regular function declaration by
# storing it in a variable. In this manner, the function can be called both by
# its name and the handle containing it.

my $name-it = sub name-it(Str $string) { say $string }

$name-it('dog'); # dog
name-it('cat');  # cat

# The `anon` keyword can be used to create an anonymous subroutine from a
# regular one. However, this forbids calling the sub by its name.

my $hello = anon sub hello(Str $name) { say "Hello, $name!" }

$hello('Joe');   # works fine
# hello('Sachio'); # error!

# Instead of anonymous subs, you can utilize anonymous block of codes called 
# pointy blocks. They are declared with an arrow `->` and their parameters lists
# must be listed without parentheses.

my $repeat-n = -> $str, $n { say $str x $n }

$repeat-n('p6', 3); # p6p6p6

# Blocks can even be more succint by dropping the arrow and using self-declared
# positional parameters (placeholders) with the twigil `$^` instead.

my $blocky1 = { say "$^a : $^b" }
my $blocky2 = { say "$^b : $^a" }

$blocky1(3, 7);     # '3 : 7'
$blocky2('A', 'Z'); # 'Z : A'

my $alt-repeat-n = { say $^a x $^b }

$alt-repeat-n('p6', 3); # 'p6p6p6'