However ridiculous it sounds, a weight is lifted from my chest.
I mean, it's nice that this sort of functionality has nice and concise operators, but I'm coming from a school of thought where overloading the equality operator should not be done lightly :)
Each operator and its overloads -- certainly built ins, users are recommended to follow suit -- conceptually maintains its own single high level semantics. Thus, while some langs have a `+` op that does numeric addition or string concat based on operand types, in Perl 6 a `+` will always mean numeric addition (unless a user breaks this convention).
`==` is always numeric value equality.
`==` does what most folk would expect between any pair of values that are a subclass of Any (the root of the type hierarchy for most purposes).
Junction is a direct subclass of Mu (the ultimate root of the type hierarchy), outside the Any hierarchy.
When a scalar operation is applied to one or more Junction values, the relevant operation is "autothreaded" over the superposed values inside the Junctions and returns a new Junction value.
If a Junction is treated as a boolean the Junction collapses to a regular single boolean value.
Junctions seem way more complex than that, first there are 4 different junction contains (any, all, one and none), second they overload 12 comparison operators each and third the other operand doesn't have to be a junction.
So e.g. any(@ar1) == any(@ar2) is an intersection but any(@ar1) == $val is a containment, and I've no idea what all(@ar1) < any(@ar2) would be, I guess it would check that max(ar1) < max(ar2)?
It seems that it just expands the lists using the operator. The output from junctions is quite nice:
> my @a = <1 2 3 4>;
> my @b = <2 3>;
> say all(@a) < any(@b);
all(any(True, True), any(False, True), any(False, False), any(False, False))
> say so all(@a) < any(@b);
False* Makes $x == 5|6 look kinda cool
* $string ~~ /<first>/ & /<second>/ & /<third>/ # matches all three regexes. huh. kinda cool
* (5|6).foo maybe we can do that in cpu-parallel (it doesn't now)? That might be kinda cool
* sub is-prime($n where $n > 2) { $n % none(2..sqrt($n)) == 0 } # Logical O(1) prime test if only you had that quantum-coprocessor? That... would be kinda cool
* ... you might notice a pattern to the motivation for this feature :)
junction1 = val1 | val2 | val3;
junction2 = val4 & val5;
if junction1 op junction2 { ... };
the compiler is free to fire off several threads, or set up a lower level SIMD parallel process, with short-circuiting, to compute the conditional result. no idea what all(@ar1) < any(@ar2) would be
Subset? > my @a = <1 2 3 4>;
[1 2 3 4]
> my @b = <2 3>;
[2 3]
> say so all(@a) < any(@b);
False
> say so all(@b) < any(@a);
TrueThing is, operators in perl6 are basically multimethods under the hood, as is pretty much everything else - so it's a much saner, more predictable thing than, say, the bag of razorblades that is perl5 overloading (which I've used to good effect, but, still, razorblades ;).
In [1]: {3,4,5} & {5,6}
Out[1]: {5}
or is there something I'm missing? > (5|4) + 1
any(6, 5)
> (5&4) + 1
all(6, 5)
> my $x = 5|4|3|2
any(5, 4, 3, 2)
> say "yep!" if $x + 2 ~~ 7
yep!
> ((2|3|4|5|6|7) & (3|4)) + 1 ~~ 5
True
> ((2|3|4|5|6|7) & (3|4)) + 1 ~~ 6
False
Kinda weird, especially & junctions. The docs[1] say "Junctions are meant to be used as matchers in boolean context; introspection of junctions is not supported. If you feel the urge to introspect a junction, use a Set or a related type instead."So far in my Perl 6 exploration I don't think I've used/needed junctions -- strikes me as a specific sort of use-case, but maybe familiarity would help me spot more (useful) opportunities.
[1] http://doc.perl6.org/type/Junction, though like all P6 docs needs more contributions
If you wanted, you could get pretty close in ruby with only a sprinkle of ill-advised metaprogramming.
> junc{5|4} + 1
any(6, 5)
> junc{5&4} + 1
all(6, 5)
> x = junc{5|4|3|2}
any(5, 4, 3, 2)
> puts "yep!" if x + 2 =~ 7
yep!
> junc{(2|3|4|5|6|7) & (3|4)} + 1 =~ 5
True
> junc{(2|3|4|5|6|7) & (3|4)} + 1 =~ 6
False
would be possible.I guess I'm just curious if this is a situation that comes up often enough to need a built in literal syntax.
http://doc.perl6.org/type/Junction
I could copy and paste the definition but it wouldn't be too helpful without context.
When it says autothread does it mean actual separate threads/CPUs?
I don't think Rakudo implements that yet, but there's quite a lot to improve first.
if all(@ages) >= 18 {
# let 'em in the club
}
Or: if any(@ages) < 18 {
# don't let 'em in the club
}
Or: if none(@ages) < 18 {
# don't let 'em in the club
}
So I use logic like the above quite a bit, however, there are plenty of areas where the above can be better if it's deeply integrated into the language. In this case, as already mentioned, it's auto-threading where appropriate. That's not an easy feature to get right if it's not baked into the language, but it's a huge win if done right.Perl 6 also has gradual typing baked in. Other languages have gradual typing as a library, but that often fails dramatically (http://blog.circleci.com/why-were-no-longer-using-core-typed...). In Perl 6, because it's built-in, not only are the failures described something Perl 6 can avoid, but there are also plenty of type checks Perl 6 can avoid at run time with integrated gradual typing (imagine that benefit in hot loops).
You could even combine that with native junction auto-threading and presumably have super-fast comparisons where the needs for checking types is eliminated at run time because it's already been done at compile time. If you do that with libraries, it's awfully tricky to get right, if not impossible.
If I look at the examples on this page https://en.wikibooks.org/wiki/Perl_6_Programming/Junctions it doesn't seem to be.
For example "if ($x == 2 || $x == 4 || $x == 5 || $x == "hello" || $x == 42 || $x == 3.14)" can be done in Perl6 as "if ($x == (2|4|5|"hello"|42|3.14))" but in Ruby this would equally easy been done with "if [2,4,5,"hello",42,3.14].include?(x)".
Ruby also has set operations defined on its container classes (e.g. [1,2,3]&[2,3,4] => [2,3]) and any?, all?, none? methods that take blocks.
Perl6 looks like a language that might have been great if it had been released in the 90s but nowadays I wonder if it will gain enough traction from non perl programmers.
[2,3,5,"hello",42,3.14].any ~~ $x
But that's not really the same, since it converts the entire array to a junction and then does the match. Really this is a lot closer: [2,3,5,"hello",42,3.14].first($x):p
Which returns the first match (as a pair (hence the :p adverb) so it won't be false even if it is a false value)... but it isn't right either because it gets mad at comparing numbers and strings (I'm asking about this in #perl6 now on irc).Ultimately: it would be trivial to port ALL Enumerable methods to Perl 6 List (or some role to cover all iterables or such), and do it in a library even if it wasn't in the core standard lib.
I'm always fascinated by how much of Ruby (and lots of other languages) are more about their Standard Lib than about their language. In the Ruby world, lots of people end up with ActiveSupport, which sprinkles in all sorts of cool stuff into the standard lib -- and I've ever seen a native 'for' loop rather than a .each in pragmatic Ruby.
But that isn't the same is it. That's only a related feature because Ruby doesn't have first class Junctions.
> I wonder if it will gain enough traction from non perl programmers.
These days people have been taught to be arrogant. To assume their language is the best. This is what makes things a tough challenge.
At least in this case, the only difference I see is that this is a language feature in Perl6 and a method from the standard lib in Ruby.
And it has to be a language feature in Perl 6 as there you don't have open classes as in Ruby or an equivalent feature for overriding operators or adding functionality to standard lib types.
I'm not sure what makes you think this. I'm not very familiar with Ruby's internals but Perl 6's MOP certainly supports modifying classes, you can add your own operators etc.
Could you provide a more explicit example?
Please take another open minded look at the examples others have posted here. Post again if you still don't see what they do that's useful and not trivially doable in any language and I'll have a go at explaining them to you.
It's not a problem with an open mind but rather with understanding what data type a junction is trying to be.
If I go to the official specification (my fault, should have gone there from the beginning), I read the definition "A junction is a superposition of data values pretending to be a single data value". But that's a fuzzy definition and it is absolutely not clear what that's supposed to mean. The given examples don't help either.
Especially when I look at this discussion and see that several people including you are not sure what "all(@ar1) < any(@ar2)" is supposed to mean. That's not a complicated expression and that's already puzzling to people who know the language?
The autothreading feature is cool but also nothing too special. Every pure functional language can implement map/reduce/filter in parallel.
tl;dr I don't see what junctions bring to the table that's not expressed easier to understand with set operations or map/reduce/filter.
Afaik junctions are simple and have an obvious intuitive read. But I'm not yet 100% confident of expressing that view without qualification. Given Estragon's "no idea" comment I allowed that my intuitive read might be bogus.
In fact the intuitive read is correct:
if all(ar1) < any(ar2)
# if all in ar1 are numerically less than any in ar2
> The autothreading feature is coolTo be clear, the whole point of junctions is autothreading; passing junctions to any code that does not have an overload for junctional arguments is automatically (semantically, at least) data parallelized and that's the win that makes them significant.
> Every pure functional language can implement map/reduce/filter in parallel.
I note "can implement" and your choice of just three functions.
Which languages provide a mechanism equivalent to junctions and their most significant use-case -- automatically generating data parallelized versions of any sequential functionally pure code?
> I don't see what junctions bring to the table that's not expressed easier to understand with set operations or map/reduce/filter.
What equivalent of "all(ar1) < any(ar2)" -- all ar1 less than any ar2 -- is "expressed easier to understand"?
More typical uses are:
die "unauthorized value" if $_ == 1|2;
grep none(1, 2), @values;
say "$a and $b are even" if ($a & $b) %% 2;
Basically : junctions are not sets. Don't try to use them for set operations. Perl 6 has a Set structure. Use that instead.The third example shows the so-called auto-threading behavior. I think it's significantly different than what you can do with sets.
A Junction in Perl 6 is "a superposition of data values pretending to be a single value". So for instance any algebraic expression can be used with a junction as if it was a scalar. The result will be a junction.
In this example the expression is $_ %% 2, which is Perl 6's way of writing the boolean statement "the variable $_ is divisible by 2". We use this expression with ($a & $b) instead of $_.
In Ruby, you could express the same with `[2,4,6].reduce(true) {|even,num| even & num.even? }` or more clearer IMO `[2,4,6].map(&:even?).reduce(&:&)`.