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.

Reply via email to