On Fri, Feb 11, 2005 at 12:54:39AM -0600, Rod Adams wrote: > Damian writes: > >Junctions have an associated boolean predicate that's preserved across > >operations on the junction. Junctions also implicitly distribute > >across operations, and rejunctify the results. > > My brain is having trouble fully grasping that. Let me attempt a paraphrase: > > Junctions exist to be tested for something. > When a test is performed, the junction is evaluated in terms of that > test. A "result junction" is created, which contains only the elements > of the original junction which will pass that given test. If the result > junction is empty, the test fails.
>From "Perl 6 and Parrot Essentials": A junction is basically just an unordered set with a logical relation defined between its elements. Any operation on the junction is an operation on the entire set. "Tests" are not used to select elements from the junction, a "test" (such as a relational op) is simply applied to the elements of the junction(s) and returns the junction of the results. In other words, if you think of a "test" as being a boolean operator, then applying a boolean operator to a junction is going to return a junction of true/false values, because boolean operators return true/false values. For example, with the "less than or equals" (<=) relational operator, the expression any(2,3,4) <= 3 becomes any( 2 <= 3, # 1 (true) 3 <= 3, # 1 (true) 4 <= 3 # 0 (false) ) which ultimately becomes any(1,0), because <= is an operator that returns booleans. In plain English, we're asking "Are any of the values 2, 3, or 4 less than or equal to 3?", and the answer is "yes", because any(1,0) evaluates to true in a boolean context. Note that it does *not* becomes the junction of the values that were less than or equal to 3 -- for that we would use C<grep>. Similarly, consider all(2,3,4) <= 3 which becomes all( 2 <= 3, # 1 (true) 3 <= 3, # 1 (true) 4 <= 3 # 0 (false) ) or all(1,0). Here, the English question is "Are all of the values 2, 3, and 4 less than or equal to 3?", and the answer is "no" (and all(1,0) evaluates to false in a boolean context). Okay, so how is this useful? Here's an example (w/apologies for any inadvertent syntax errors): if (any(@age) >= 100) { say "There's a centenarian here!"; } is somehow a lot nicer than if (grep { $^x >= 100 } @age) { say "There's a centenarian here!"; } And if (all(@age) >= 100) { say "We're all centenarians here!"; } is much nicer than if (!(grep { $^x < 100 } @age)) { say "We're all centenarians here!"; } But wait, there's more! Junctions are valuable because we can combine them into multiple operands or function arguments. Thus, # intersection: Are any values in @foo also in @bar? any(@foo) == any(@bar) # containment: Are all of the elements in @foo also in @bar? all(@foo) == any(@bar) # non-intersection: Are all of the elements in @foo not in @bar? all(@foo) == none(@bar) Here's that last one spelled out to see the effects, assuming @foo=(2,3,4) and @bar=(5,6): all(2,3,4) == none(5,6) -> all( 2 == none(5,6), 3 == none(5,6), 4 == none(5,6) ) -> all( none(2==5, 2==6), none(3==5, 3==6), none(4==5, 4==6) ) -> all( none(0, 0), none(0, 0), none(0, 0) ) Of course, the value of junctions is that they work pretty much with any operation on scalar arguments. Thus, if we define an is_factor() function as: # return true if $x is a factor of $y sub is_factor (Scalar $x, Scalar $y) { $y % $x == 0 } then we automatically get: # are any of @foo factors of $bar? if is_factor(any(@foo), $bar) { ... } # are all of @foo factors of $bar? if is_factor(all(@foo), $bar) { ... } # is $foo a factor of any elements of @bar? if is_factor($foo, any(@bar)) { ... } # is $foo a factor of all elements of @bar? if is_factor($foo, all(@bar)) { ... } # are any elements of @foo factors of any elements of @bar? if is_factor(any(@foo), any(@bar)) { ... } # are all elements of @foo factors of all elements of @bar? if is_factor(all(@foo), all(@bar)) { ... } # a (somewhat inefficient?) is_prime test for $bar if is_factor(none(2..sqrt($bar)), $bar) { say "$bar is prime"; } Just because I'm curious, here's the the prime test spelled out for $bar==23, testing if 23 is a prime number: is_factor(none(2..sqrt(23)), 23) -> is_factor(none(2..4), 23) -> { 23 % none(2..4) == 0 } -> { none( 23 % 2, 23 % 3, 23 % 4 ) == 0 } -> { none( 1, 2, 3 ) == 0 } -> { none( 1==0, 2==0, 3==0 ) } -> { none( 0, 0, 0) } -> true That is just too cool. :-) Pm