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))]
.
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))]
.
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.
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'));
This is intentional, as far as I know.
Imagine $j containing a Junction of hashes: then $j.values would be a junction of Seq's, not the hashes themselves.
If you want the array of a junction, then maybe you should start from an array, and build a junction out of that:
my @a = 1,2,3,4,5;
my $j = any(@a);
If you really want to go the Junction -> Array way, you could, but it would involve using nqp, and that's something I would not recommend in userland code.
my $j = any my @a = 1,2,3,4,5;
–
Tripper 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.
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'));
There's a way to thread a junction of Mu
so as to build an Array
of eigenstates with their containers preserved. Because Mu
is a supertype of the Any
that autothreading is oriented towards, we can't depend on that feature while covering all possible eigenstate types, however.
Mu.ACCEPTS
has a multi method ACCEPTS(Mu:U: Junction:D) is default
candidate to allow for smartmatches of junctions against any type object. This allow for a manual threading if fed a thunk that can recurse over ACCEPTS
to be chained with CALL-ME
, which can thread over its invocant:
class Unison is Mu is repr<Uninstantiable> {
method CALL-ME(Mu $topic is raw --> Array:D) {
my @list;
proto sub push(Mu) {*}
multi sub push(Mu $topic is raw) { @list.BIND-POS(@list.elems, $topic) }
multi sub push(Junction:D $junction) { self.ACCEPTS($junction).(&push) }
self.ACCEPTS($topic).(&push);
@list
}
multi method ACCEPTS(Mu $topic is raw) {
-> &accept { accept $topic }
}
}
say Unison(1 | 2 | 3 | 4 | 5); # OUTPUT: [1 2 3 4 5]
say Unison((1 | (2, 3) & 4) ^ 5); # OUTPUT: [1 (2 3) 4 5]
ACCEPTS
must not be overridden in its entirety, but since Mu
is the parent and not Any
, just the one Mu
candidate can cover its bases. This will only work on a type object invocant, so this is given the Uninstantiable
REPR.
© 2022 - 2024 — McMap. All rights reserved.