Raku Programming/Junctions

Junctions

edit

Junctions were originally implemented as part of a fancy Perl module to simplify some common operations. Let's say we have a complex condition where we need to test variable $x against one of several discrete values:

if ($x == 2 || $x == 4 || $x == 5 || $x == "hello" 
 || $x == 42 || $x == 3.14)

This is a huge mess. What we want to do is basically create a list of values and ask "if $x is one of these values". Junctions allow this behavior, but also do so much more. Here's the same statement written as a junction:

if ($x == (2|4|5|"hello"|42|3.14))

Types of Junctions

edit

There are 4 basic types of junctions: any (logical OR of the components), all (logical AND of all components), one (logical XOR of all components), and none (logical NOR of the components).

List Operators

edit

List operators construct a junction as a list:

my $options = any(1, 2, 3, 4);        # Any of these is good
my $requirements = all(5, 6, 7, 8);   # All or nothing
my $forbidden = none(9, 10, 11);      # None of these
my $onlyone = one(12, 13, 4);         # One and only one

Infix Operators

edit

Another way to specify a junction is to use infix operators like we have already seen:

my $options = 1 | 2 | 3 | 4;        # Any of these is good
my $requirements = 5 & 6 & 7 & 8;   # All or nothing
my $onlyone = 12 ^ 13 ^ 4;          # One and only one

Notice that there isn't an infix operator to create none() junctions.

Operations on Junctions

edit

Matching Junctions

edit

Junctions, like any other data type in Raku, can be matched against using the smart match operator ~~. The operator will automatically perform the correct matching algorithm depending on which type of junction is being matched.

my $junction = any(1, 2, 3, 4);
if $x ~~ $junction {
    # execute block if $x is 1, 2, 3, or 4
}

all() Junctions

edit
if 1 ~~ all(1, "1", 1.0)     # Success, all of them are equivalent
if 2 ~~ all(2.0, "2", "foo") # Failure, the last one doesn't match

An all() junction will only match if all the elements in it match the object $x. If any of the elements do not match, the entire match fails.

one() Junctions

edit

A one() junction will only match if exactly one of its elements match. Any more or any less, and the entire match fails.

if 1 ~~ one(1.0, 5.7, "garbanzo!") # Success, only one match
if 1 ~~ one(1.0, 5.7, Int)         # Failure, two elements match

any() Junctions

edit

An any() junction matches so long as at least one element matches. It could be one or any other number but zero. The only way for an any junction to fail is if none of the elements match.

if "foo" ~~ any(String, 5, 2.18)  # Success, "foo" is a String
if "foo" ~~ any(2, Number, "bar") # Failure, none of these match

none() Junctions

edit

none() junctions only succeed in a match if none of the elements in the junction match. In this way, it's equivalent to the inverse of the any() junction. If any() succeeds, none() fails. If any() fails, none() succeeds.

if $x ~~ none(1, "foo", 2.18)
if $x !~ any(1, "foo", 2.18)    # Same thing!