[Chicago-talk] [PERL6]: Fun with junctions (was Sets vs Junctions)
Andy_Bach at wiwb.uscourts.gov
Andy_Bach at wiwb.uscourts.gov
Mon Feb 14 13:01:08 PST 2005
I don't know if anybody *else* is on the edge of their seat, await P6 but
... I ran into the "Perl 6 and Parrot Essentials" book at a used book
store and so ended up on the P6 lists. Its not your mother's perl
anymore; well, it will be (it'll have full P5 compatability somehow), but
its a whole lot more. One new feature are junctions:
http://dev.perl.org/perl6/synopsis/S09.html
set-like, array like, yet w/ their own set of operations, like "any" and
"all" ... below is a nice summary of what junctions are and why we want
them.
a
Andy Bach, Sys. Mangler
Internet: andy_bach at wiwb.uscourts.gov
VOICE: (608) 261-5738 FAX 264-5932
"Bugs happen. A bug is a test case you haven't written yet."
Mark Pilgrim
----- Forwarded by Andy Bach/WIWB/07/USCOURTS on 02/14/2005 02:48 PM -----
"Patrick R. Michaud" <pmichaud at pobox.com>
02/11/2005 01:22 PM
To
Rod Adams <rod at rodadams.net>
cc
"perl6-language at perl.org" <perl6-language at perl.org>
Subject
Fun with junctions (was Sets vs Junctions)
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
More information about the Chicago-talk
mailing list