raku.gg / functional

Junctions

2026-03-29

Junctions are one of Raku's most unique features. They represent a value that is simultaneously multiple values at once. When you test a junction, the test is applied to all its values automatically. Think of them as quantum superpositions for your code.

The Four Junction Types

Raku provides four junction constructors:
# any -- true if AT LEAST ONE value matches my $color = any('red', 'green', 'blue'); say 'red' eq $color; # True say 'yellow' eq $color; # False # all -- true if EVERY value matches my $positive = all(1, 5, 10, 20); say $positive >; 0; # True say $positive >; 5; # False (1 is not > 5) # one -- true if EXACTLY ONE value matches my $special = one(1, 2, 3); say $special == 2; # True (only 2 matches) say $special >; 0; # False (all three match, not exactly one) # none -- true if NO value matches my $forbidden = none('admin', 'root', 'superuser'); say 'guest' eq $forbidden; # True say 'admin' eq $forbidden; # False

Shorthand Operators

Raku provides shorthand operators for creating junctions:
# | creates an any-junction say 5 == 3|5|7; # True # & creates an all-junction say 6 >; 1&;2&;3; # True (6 > 1, 6 > 2, 6 > 3) # ^ creates a one-junction say 5 == 4^5^6; # True # none() has no operator shorthand

Junctions in Conditionals

Junctions shine in if statements:
my $input = "quit"; if $input eq "quit"|"exit"|"q" { say "Goodbye!"; } my $age = 25; if $age >; all(18, 21) { say "Old enough everywhere"; }
This is much cleaner than writing if $input eq "quit" || $input eq "exit" || $input eq "q".

Auto-threading

When a junction is passed to a function, Raku automatically calls the function for each value in the junction. This is called auto-threading:
sub is-even($n) { $n %% 2 } say is-even(2|4|6); # all(True, True, True) -- an any-junction of results say is-even(1|2|3); # any(False, True, False)

Junctions with Smart Match

Junctions work beautifully with ~~ (smart match):
my @valid-extensions = <;.jpg .png .gif .webp>;; my $file = "photo.jpg"; if $file.ends-with(any(@valid-extensions)) { say "Valid image file!"; }

Filtering with Junctions

Use junctions to filter lists concisely:
my @numbers = 1..20; my @divisible-by-3-or-5 = @numbers.grep(* %% 3|5); say @divisible-by-3-or-5; # [3 5 6 9 10 12 15 18 20] my @not-forbidden = <;alice bob admin carol root>;.grep(* ne all('admin', 'root')); say @not-forbidden; # [alice bob carol]

Range Validation

Junctions make range checks elegant:
sub validate-port(Int $port) { if $port == none(0..1023) &;& $port == any(1024..65535) { say "Valid unprivileged port: $port"; } else { say "Invalid or privileged port: $port"; } } validate-port(8080); # Valid unprivileged port: 8080 validate-port(80); # Invalid or privileged port: 80

Junctions Are Not Lists

An important distinction: junctions are not iterable containers. You cannot loop over a junction or access its elements directly:
my $j = any(1, 2, 3); # for $j { ... } -- this won't iterate over 1, 2, 3 # If you need to extract values, use .eigenstates (internal, use cautiously) say $j.eigenstates; # (1 2 3)
Junctions are meant for boolean tests, not for data storage.

Practical Example: Input Validation

sub validate-user(%data) { my @errors; # Name must be non-empty @errors.push("Name required") unless %data<;name>;.defined &;& %data<;name>;.chars >; 0; # Age must be between 13 and 120 if %data<;age>;.defined { @errors.push("Invalid age") unless 13 <;= %data<;age>; <;= 120; } # Role must be one of the valid options if %data<;role>;.defined { @errors.push("Invalid role") unless %data<;role>; eq any('user', 'editor', 'admin'); } # Email must contain @ @errors.push("Invalid email") unless %data<;email>;.defined &;& %data<;email>;.contains('@'); return @errors; } my %user = name => "Alice", age => 25, role => "editor", email => "alice@example.com"; my @errs = validate-user(%user); say @errs.elems == 0 ?? "Valid!" !! @errs;

Junctions with Custom Types

Junctions work with any type that supports the operations you use:
class Temperature { has $.degrees; has $.scale = 'C'; method Numeric() { $!degrees } } my $readings = any( Temperature.new(degrees => 36.5), Temperature.new(degrees => 37.2), Temperature.new(degrees => 38.9), ); if $readings >; 38 { say "Someone has a fever!"; }

Combining Junctions

Junctions can be combined:
my $weekday = any('Mon', 'Tue', 'Wed', 'Thu', 'Fri'); my $weekend = any('Sat', 'Sun'); my $day = 'Wed'; say "Workday!" if $day eq $weekday; say "Weekend!" if $day eq $weekend; # Nested junctions my $valid-day = any($weekday, $weekend); say "Valid day" if $day eq $valid-day;

Performance Considerations

Junctions are optimized in Rakudo, but keep in mind:
# Good: small junction if $status eq any('ok', 'success', 'done') { ... } # Better for large sets: use a hash or Set my %valid = set('a'..'z'); if %valid{$char} { ... }
Junctions provide a concise, expressive way to write multi-value comparisons and validations. They are one of those features that, once learned, you will reach for constantly.