Search code examples
arraysrakujunction

How to return the values in a junction as an array?


Define a junction my $j = 1 | 2 | 3 | 4 | 5, now I want to get an array of its value [1 2 3 4 5], how should I implement this?

I tried $j.values but Perl6 gave me the whole junction as an element: [any((1), (2), (3), (4), (5))].


Solution

  • As Håkon Hægland already pointed out, this is not something you're supposed to do:

    Junctions are meant to be used as matchers in boolean context; introspection of junctions is not supported. If you feel the urge to introspect a junction, use a Set or a related type instead.

     -- docs.perl6.org/type/Junction

    However, it is possible.

    First, you can use authothreading (ie the automatic evaluation of each branch of a junction when passed to a function that expects an argument of type Any):

    sub unjunc(Junction $j) {
        gather -> Any $_ { .take }.($j);
    }
    

    Second, you can poke into the guts and manually extract the values:

    sub unjunc(Junction $j) {
        multi extract(Any $_) { .take }
        multi extract(Junction $_) {
            use nqp;
            my $list := nqp::getattr($_, Junction, '$!storage');
            my int $elems = nqp::elems($list);
            loop (my int $i = 0; $i < $elems; $i = $i + 1) {
                extract nqp::atpos($list, $i);
            }
        }
        gather extract $j;
    }
    

    If your junction is non-recursive (ie does not contain other junctions you want to flatten), the latter approach can be simplified:

    my $j := 1|2|3;
    say nqp::p6bindattrinvres(nqp::create(List), List, '$!reified',
        nqp::getattr($j, Junction, '$!storage'));