I spent a fair amount of time with Rakudo over the holiday break (see http://dave.whipp.name/sw/perl6 for the writeup). I was generally impressed with both the language and its implementation. There were, unsurprisingly, a bunch of things missing. Some of these were things that are in the spec, but not yet in Rakudo. Others are things that feel important, but which could be added later, via modules. But one omission, junctional collapse, appears to me to require core language support: it is not a feature that can be added as a user module.

The term "collapse" is a metaphor taken from quantum mechanics. It is apt, because the concept of the "values" of a junction makes sense only in the context of the action of an operator on the junction. It is my proposal that we add a new meta-operator to S03 that acts to apply other operators (equality and inequality tests) to junctions:

  @domain  |op| $junction --> @values  ## junction-collapsing "grep"
  @domain !|op| $junction --> @values  ## it's negated partner

The operator has the semantics of a "grep", but with the ability to handle infinite ranges in finite time. The reason for this should become apparent from a motivating example. Consider a blackjack hand: a set of cards where the value of aces is either 1 or 11. The total value of a hand can be described as a junction:

  my $ace = 1 | 11;
  my $seven = 7;
  my @hand = $ace xx 3, $seven;
  my $junc_value = [+] @hand;  ## any( 10, 20, 30, 40 )

There are a bunch of possible values in the junction. The one we care about is the largest that is not greater than 21. Using Perl6 as it stands today, the way to extract this value is brute force:

  my $concrete_value = max (0..21).grep: { $^score == $junc_value };

This will work, but doesn't scale. Imagine we wanted all the possible values, and know nothing about their domain:

  my @all_values = (-Inf..Inf).grep: { $^score == $junc_value };

This code has an obvious performance problem that would be tricky to optimize away! And that problem is the justification of my assertion that junctional collapse requires core language support. Using a "grep" meta operator:

  my $concrete_value = max 0 .. 21 |==| $junc_value;
  my @all_values = -Inf .. Inf |==| $junc_value;

the infinite range can be handled correctly.

Adding a new meta-operator should not be undertaken lightly. I believe that the collapse of junctions is a necessary feature of the language, and one that cannot be added as a user-module. Furthermore, alternatives such as a "eigenvalues" method on the Junction class fail to address the core property of junctions that their value depends on the operator that is used to observe them.

Another hurdle that the meta operator must overcome it to demonstrate that it is sufficiently general. If the only values of "op" was "==", then we wouldn't need a "meta". Also, the operator has application beyond collapsing junctions. Some more examples:

  say ^Inf |>| one 4 .. Inf; ## result == 5

  say @lines |~~| /word/;    ## no junction: a standard "grep"


An additional feature -- not part of my core proposal, but one that I think would add value -- would be to allow a typename to be used as the LHS domain, in place of an infinite range:

  say ::Str  |eq|  any < foo bar baz >; ## match against all strings
  say ::Str !|ne|  all < foo bar baz >; ## same result
  say ::Str !|eq| none < foo bar baz >; ## same again!

or a finite range:

  subset BJ_score where { $_ == any 0 .. 21 };
  say "score is { max( ::BJ_score |==| $junc_score ) // "bust" }"


I'd like to think that this proposal is an obvious way to meet a necessary need. Even if this exact approach is not chosen, I hope to have at least convinced you that core language support is needed to extract the "values" of a junction; and that a "Junction::eigenvalues" method is not the correct way to achieve this.


Dave.

ps. The reason for choosing vertical bars, |op|, as the meta-op syntax is partly by analogy to the concept of "absolute value" that mathematicians express using vertical bars; and partly a less-cute distillation of a "bra-ket" suggestion I make in the writeup that I referenced above.

Reply via email to