Raku: a language where a value can have several values at once (Part 2)

Last time we saw that a junction is something you may treat as a single value, even though it’s more than that. For example, you can add a number to three numbers at once:

my $j = 1 | 2 | 3;
($j + 10)>>.say; # 11, 12, 13, one per line

Knowing this helps us to use junctions in more complex contexts, for example, as a condition in grep or map:

say (1 .. 999).grep(* %% (3 | 5)).sum;

Here, we compute the sum of all the numbers from 1 to 999 that are divisible by 3 or 5 (999 inclusive).

A similar example with strings and first:

my @langs = <Cobol Pascal Perl Raku PHP Python>;
say @langs.first(*.lc eq any(<perl raku>)); # Perl
say so 'Cobol' eq any(@langs); # True

Here’s a more practical example, where a filename extension is tested without using regexes:

my $file = 'photo.bmp'; 
say so $file.ends-with('.jpg' | '.png' | '.gif'); # False

And this is, in fact, yet another demonstration of the TIMTOWTDI principle. You are free to choose between regexes and junctions:

my $title = 'Raku junctions explained';
say so $title.contains('Perl' | 'Raku');
say so $title.lc.contains(all <raku junction>);
say so $title.contains(none <Java Python>);

The next example selects only the Raku-related files from a list:

my @files = <main.raku notes.txt Lib.rakumod logo.png test.t>;
say @files.grep(*.ends-with: any <.raku .rakumod .t>);

Now let’s use junctions in another kind of comparison, again in places where a single value is normally expected:

for <y no Yes maybe> -> $answer {
    given $answer.lc {
        when 'y' | 'yes' { say "$answer: agreed" }
        when 'n' | 'no'  { say "$answer: refused" }
        default          { say "$answer: ?" }
    }
}

More types

Junctions work with other data types too. For example, you can use type names directly to test a variable:

for 42, 'hi', 3.14, True -> $x {
    say "$x is {$x.^name}", ': ', ($x ~~ Int | Str ?? 'is' !! 'isn\'t'), ' Int or Str';
}

Note that a Boolean value is also an Int:

42 is Int: is Int or Str
hi is Str: is Int or Str
3.14 is Rat: isn't Int or Str
True is Bool: is Int or Str

Applying | to ranges is less obvious, but it works as expected:

for 2, 5, 8 -> $n {
    say "$n: ", ($n ~~ (1..3) | (7..9) ?? 'edge' !! 'middle');
}

And a trick for the classic FizzBuzz task:

for 1 .. 15 -> $n {
    say do given $n {
        when * %% (3 & 5) { "$_ FizzBuzz" }
        when * %% 3       { "$_ Fizz" }
        when * %% 5       { "$_ Buzz" }
        default           { $n }
    }
}

Instead of comparing the topic variable with both 3 and 5, you can compare it with 3 & 5. The program prints the correct output:

1
2
3 Fizz
4
5 Buzz
6 Fizz
7
8
9 Fizz
10 Buzz
11
12 Fizz
13
14
15 FizzBuzz

By the way, don’t forget that Raku is such a powerful language that you can create a grammar to parse Python and run a FizzBuzz.py program in a browser.

Not to mention that you can use Raku even if you don’t have it installed on your computer.

Leave a Reply

Your email address will not be published. Required fields are marked *

Retype the CAPTCHA code from the image
Change the CAPTCHA codeSpeak the CAPTCHA code