Damian Conway wrote:

Rod Adams wrote:

The overall impression I'm getting here is that we need some syntax for saying:

$x = any(1..1000) such_that is_prime($x);


In standard Perl 6 that'd be:

  $x = any(grep {is_prime $^x} 1..1000);

or, if you prefer your constraints postfixed:

$x = any( (1..1000).grep({is_prime $^x}) );

Both of those seem way too brutal to me.


We then can say that any junction stored in a var stays constant, until explicitly reassigned. Just like every other kind of thing we store.


Yep. That's exactly what we'll be saying!

Good.


Philosophy Question:

What's the difference between a junction and an array containing all the possible values of the junction?


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.


Looking at the S09 C<< substr("camel", 0|1, 2&3) >> example explains a lot.


So, on that train of thought, would this make sense:

if $x == @x.any {...}
if $x == @x.none {...}


Probably. It's entirely possible that, in addition to being built-in list operators, C<all>, C<any>, C<one>, and C<none> are also multimethods on Scalar, Array, and List.

okay.


------


Now that I've gotten some feedback from my original message (on list and off), and have had some time to think about it some more, I've come to a some conclusions:


  Junctions are Sets.  (if not, they would make more sense if they were.)

  Sets are not Scalars, and should not be treated as such.

  If we want Sets in Perl, we should have proper Sets.

Let's first define what a Set is:
- A Set is an unordered collection of elements in which duplicates are ignored.
- There are really only two questions to ask of a Set: "Is X a member of you?", and "What are all your member?"
- Typically, all members of a set are of the same data type. (I'm in no way committed to this being part of the proposal, but it makes sense if it is)


Sets and Lists are two different things. Lists care about order and allow duplicates. Iterating a Set produces a List, and one can convert a List into a Set fairly easily.

Sets and Hashes are quite similar, but in other ways different. The keys of a Hash are a Set of type String. In addition to the String constraint, each element of the set has an additional scalar value associated with it. Hashes can be multidimensioned. I have no idea what a multidimensional Set is. It may be possible to represent Sets as lightweight Hashes if the "Strings for keys" constraint is lifted or altered, but I see several advantages to Sets being distinct, for reasons I'll outline below.


So I propose making Sets a first class data type right up there with Arrays, Hashes, and Scalars. For the purposes of this posting, I will assume that they get a sigil of #. (to get a comment, you need whitespace after the #). I harbor no expectations that it will stay as this, but I needed something, and didn't feel like remapping my keyboard at the moment. Interestingly, on US keyboards, @#$% is shift-2345.


With that, we can now make existing operators do nifty things:

#a = #b + #c;    # Union         (Junctive $b or $c)
#a = #b - #c;    # Difference    (         $b and not $c)
#a = #b * #c;    # Intersection  (         $b and $c)

#a == #b;        # Do sets contain the same values?
#a <  #b;        # Is #a a subset of #b? likewise >, <=, >=


$a ~~ #b; # Membership #a += $b; # Add value to set

#a = @b;         # Create a set from an array/list
#a = (1,2,3);

$ref = #{1..10}; # an anonymous Set reference

@a = #b;         # One way to iterate the members.

It's probably best to define binary | and & as "Set Creation with Union/Intersection", so we have:

#a = 1|3|7;
#a + @b == #a | @b;

We also add some methods here and there:

@a = #b.values;
#b = @a.as_set;
$a = #b.elems;
my str #a = %b.keys;


I also envision "virtual sets", which cannot be iterated, but can be tested for membership against. These would be defined by a closure or coderef.


#natural_numbers = { $^a == int($^a) && $^a > 0 };
#primes = &is_prime;

Set operations with virtual sets should be able to define new closures based on the former ones:

#a = #b + #c;  ==>  #a = {$^a ~~ #b || $^a ~~ #c};
#a = #b * #c;  ==>  #a = {$^a ~~ #b && $^a ~~ #c};
#a = #b - #c;  ==>  #a = {$^a ~~ #b && $^a !~ #c};
#a = #b + 3;   ==>  #a = {$^a == 3  || $^a ~~ #b};


So now, some sample code:

$x = any( (1..1000).grep({is_prime $^x}) ); # Damian's example from above
 vs
#x = (1..1000) * #primes;


if $x == 1|2|3 {...} vs if $x ~~ 1|2|3 {...} or if $x ~~ #{1,2,3} {...}

$x = (any(2,3,4,5) and any(4,5,6,7));
# where $x == any(2,3,4,5)
vs
#x = #{2,3,4,5} * #{4,5,6,7};
# where #x == #{4,5}


if 3 < $a < 4 {...} # where $a is junctive # given the length of discussion here, this a very confusing concept. vs if 3 < #a.max && #a.min < 4 {...} # or whatever semantics you actually expected!


for #a -> $a {...} # if non-virtual # might auto-thread


I'll be glad to provide other sample conversions if requested.

As for the original purpose of Junctives, back whenever they were first presented, one can declare that the type of an object is in fact a Set of types, which may be just one element, or more. (or even none?!?) You would want to restrict it to a Set of Class, or some such thing, so you don't get someone attempting to create an object of type 3.8.


Why I like Sets better than Junctions:
- No surprises. You know exactly what you're getting at any given point.
- Sets are very common computing concepts, so most programmers will understand them immediately.
- The resulting code is much easier to read and write, IMHO.


Why they merit a new sigil:
- They are structurally and semantically different from Scalars, Arrays, and Hashes.
- They are integral to the language design, and basic enough to make shuffling them into a separate class dubious at best.




-- Rod Adams





Reply via email to