Raku Programming/Junctions

Junctions

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

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

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

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.

Matching Junctions

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

```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

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

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

`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!
```