I've been thinking about junctions, and I believe we may need a small
tweak to (at least) the jargon in one part of the specification.
Specificially, in S32-setting-library_Containers.pod, we currently have:
=item !eigenstates
method !eigenstates (Junction $j: --> Parcel)
Returns an unordered list of the values that constitute the junction
(formerly called C<.values>). It flattens nested junctions of the
same type, so C<(1|(2|3)).eigenstates> returns an arbitrary
permutation of the list C<1, 2, 3>.
The problem is the *name* of that method. By definition, the "eigenstates"
of a junction are those non-superimposed values to which the junction's
superimposed values could actually collapse. Or, to put it another way,
those non-superimposed values that a junction would actually match.
That is, a C<$value> is an eigenstate of a C<$junction> if-and-only-if:
$value !~~ Junction && $value ~~ $junction
But the C<!eigenstates> method (as currently defined) does not return
a list of such eigenstates. Instead it merely returns a partially-flattened
list of the raw "internal values" of the junction...which is not (usually) the
same thing at all.
That's because junctions often contain internal values to which *externally*
they cannot actually collapse...and hence cannot actually match.
Some examples, to illustrate the distinction:
Internal states Actual eigenstates
Junction (what !eigenstates returns) (what junction could match)
============= =========================== ===========================
any(1,2,3) 1, 2, 3 1, 2, 3
all(1,2,3) 1, 2, 3 <none>
one(1,2,3) 1, 2, 3 1, 2, 3
none(1,2,3) 1, 2, 3 <infinitely many>
any(1&2, 2&3) all(1,2), all(2,3) <none>
all(1|2, 2|3) any(1,2), any(2,3) 2
one(1|2, 2&3) any(1,2), all(2,3) 1, 2
one(1|2, 2|3) any(1,2), any(2,3) 1, 3
So the two problems are:
1. $j!eigenstates doesn't return $j's eigenstates
(i.e. the method is misnamed)
2. $j!eigenstates doesn't return $j's eigenstates
(i.e. there's no way to get a junction's actual eigenstates,
which is a very useful thing to be able to do--see below)
Problem 1 could be solved by renaming the method C<!eigenstates>
to something like: C<!internal-states>. And, of course, renaming the
corresponding attribute in the Junction class from C<$!eigenstates>
to something like C<$!internal-states>.
Problem 2 could be solved by defining a new (and public!)
C<.eigenstates> method in the Junction class. This method
would be implemented as something like:
method eigenstates(Junction $j: --> List) is cached {
# No feasible way of representing the eigenstates of an injunction...
fail if $j!type ~~ JUNCTION_TYPE_NONE;
# Candidates for eigenstates are all the junction's internal values...
my @possible-eigenstates = $j!internal-states;
# Or, rather, candidates are all its *non-superimposed* internal values
# so we need to iteratively flatten any superimposed values...
@possible-eigenstates
.= map({$^value ~~ Junction ?? $^value!internal-states !! $^value})
while @possible-eigenstates.grep(Junction);
# Actual eigenvalues are those unique candidates
# that successfully match the original junction...
return uniq(@possible-eigenstates).grep($j);
}
There is no need for this new C<.eigenstates> method to be private,
because it doesn't expose the internal data of its junction object,
but rather calculates a useful external property of that object.
Some examples of why that the actual eigenstates of a junction are useful
(note that these all assume the above (re)definition of C<.eigenstates>):
# Find the list of common elements in two lists...
sub intersection (@list1, @list2) {
(any(@list1) & any(@list2).eigenstates;
}
# Find the factors of a number...
sub factors (Num $n) {
( $n/any(1..$n) ).eigenstates.grep({ $^q.Int == $q });
}
# Check for an unacceptable password, and list all when warning...
constant UNACCEPTABLE = any < Godel Escher Bart etc... >;
if $passwd ~~ UNACCEPTABLE {
say "Unacceptable password. Don't use any of these:";
say UNACCEPTABLE.eigenstates¬».fmt("\t%s\n");
}
If nothing else, we really do need to rename the current C<!eigenstates> method.
Damian
PS: I also note that the most recent release of Rakudo* defines the
C<.eigenstates> method as public, which is inconsistent with the
current specification. That probably needs to be fixed as well.