Damian Conway wrote:

Rod Adams wrote:

This is my major point of the post. In my opinion, your example of:

   # Print a list of substrings...
   my $substring = substr("junctions", any(1..3), any(3..6));
   say $substring.values();

Is a perfect example of a place where saying:

   # Print a list of substrings...
   my @substring = substr("junctions", »1..3«, »3..6«);
   say @substring;

Is far more in line with what you're doing.


But much less obvious. This is the core of my qualms. You're proposing we have all three of:

    »foo«  @x,   @y;
         foo  [EMAIL PROTECTED], [EMAIL PROTECTED];
         foo  [EMAIL PROTECTED]    @y»;

all meaning very different things. That really worries me. I'd especially prefer that we didn't overload »« to mean both "linear vector" and "cross-product".

I certainly like the idea of having both abilities available; I'm just think the syntaxes need to be better differentiated.

I'm not pinning everything on the syntax being » «. I just hadn't heard the objection to it before so was running with it. If it takes changing them to something else, I'll go with that. Though I was hoping for something shorter than C<every()>. I also like the use of operators here, since they are making a substantial change to the entire statement. All of any/all/one/none/every look too much like ordinary function calls for my tastes. But we do seem to be mighty short on unambiguous punctuation these days.


However, I would have picked the « » as qw// to be the loser in this regard. Then the »'s and «'s all mean "repetition is happening". I personally never found C< $x{qw/dog cat foo/} > to be a bother, and I use the equivalent in Perl5 very frequently. _If_ that is dropped, then you can have « » mean "linear vector" and » « mean "cross product". But I won't press this idea.

As for "obvious", I was processing two lists of parameters, and got back a 2-D array, where I could easily match up each input to result.
You returned something of the form any(any(),any(),any()), where there is no way to match which result was from a given input.
(FWIW, we both get garbage for output and/or errors. You're printing raw junctions, I'm printing arrayrefs.)


I would wager that most people attempting this sort of thing would find a 2-D array to be a much more obvious result than a nested junction.


Simply put, you're ignoring the fact that junctions have a boolean predicate. Which they do.


Yep. Isn't it useful that you can do that, and get more functionality out of a single construct?

Powerful? Yes.

Scary? Very. I start with something that looks like a scalar, and all the code it touches turns all my other variables into juxtapositions. Kind of like taint checking.

Useful? No more so that hyperquotes in the same place.

I find it more useful to get even more functionality out of the list construct.



I need to think about this. I'm not sure I'm convinced this isn't covered by none(Junction) typing on parameters.



It is not.

By my proposal:

   $j = any(1,2,3);
   unless say($j) { die '...' }

The say would thread, because of the boolean expression in the 'unless'. C< say > does not get the junction as a parameter. But C< say > needs to be marked that it's a no-no to thread over it.


But that was precisely my point:

sub say (none(Junction) [EMAIL PROTECTED]) {...}


In my way, C< say > is never given the chance to accept or decline $j as an argument. The above would be handled as:

   unless any(say(1), say(2), say(3)) {...}

All C< say > sees is scalars, one at a time. I was looking for a way to mark C< say > with a way to tell the callee that threading over it (note: "over" not "through") is a bad idea.


I am completely convinced of this. Please express your reservations so I can address them.


    sub get_matches {
         my @in  = split /<ws>/, prompt 'search for: ';
         my @out = split /<ws>/, prompt 'but not: ';
         return %data{any(@in) & none(@out)};
    }


my $data = get_matches();

No booleans anywhere in sight.


So with example data:

   @in = qw/foo bar baz/;
   @out =  qw/baz fiz bop/;
   %data = (foo => 5, bar => 6, baz => 7, fiz => 5, bop => 8);

you return:

   all(any(5,6,7), none(7,5,8))

Which is just 6. If I were a user of this function, I would want foo's 5 as well. And I'd probably prefer to have had them as a list, not a junction.

By delaying the application of your predicates, you have voided whatever it was that made those values have those predicates associated with them. Logic would say that each step of processing of the values in the junction without the application of the predicate would more often than not move you further and further away from the correct meaning of the predicate in terms of those values.

This is why I want to stop "junction propagation". The more you feed code junctions that create other junctions, the more obscure your final result is. The predicate is there to explain how to recombine the results of threading together to form a single result. Attempting to evaluate the values without evaluating the predicate as well seems incredibly error prone to me. By forcing the predicate to be evaluated, we generate no new junctions... just results.

So perhaps a better rephrasing of the Prime Rule would be: Every legal junction evaluation must include the evaluation of it's predicate.


I would be in favor of adding non-boolean predicates. For instance, some Numeric predicates could be: min, max, sum, mode, median, mean, stdev. String predicates could be: min, max, longest, shortest. Basically any function which can take several results and merge it into a single value again can be a predicate.




BTW, this example is what sets are good for:

   sub get_matches {
        my @in  = split /<ws>/, prompt 'search for: ';
        my @out = split /<ws>/, prompt 'but not: ';
        return %data{set(@in) - set(@out)};
   }


I consider the Prime Rule as essential to junction sanity.


I consider it an unnecessary and unhelpful restriction on the utility of junctions.

It's a better safeguard for the unaware than anything else I've seen.



Without it, you're free to ignore that predicate


Yep.


If you're ignoring the predicate, a junction is just a list of values.


No. You can ignore the predicate because you don't need it *yet*.

Then don't affix a predicate to that group of values *yet*.

In my mind it's quite clear that by binding the values to a predicate, you are saying they belong together. Therefore, to evaluate the junction, you have to evaluate it's entirety, not some intermediate results. If you're not ready to commit to the predicate yet, don't bind to it. Once you're bound, you should be stuck unless you do an explicit C< $j.values() > or the like.


Treat it as such. A list. Hyperquotes will deal with those situations nicely, though explicitly.


No they don't. See my C<get_matches> example above.

Indeed, while admittedly my hyperquotes do not provide an elegant solution there, your junctions appear not to provide an elegant working solution there, either.


The solution to the C<get_matches> problem is to use either sets or grep. And since grep performs boolean tests, feel free to use the junctions listed in there.


And I'm still very concerned that using hyperquote to parallelize functions and data *in different ways* will make the autothreading syntax harder to understand and differentiate.

I'm confident in the ability of this list (in whole or in part) to come up with a decent syntax once it's agreed to do so.



PS: I'll be away for the rest of the week, but will happily continue to argue when I return. ;-)

Best of luck with whatever draws you away. And thanks for the heads up, so I knew why you stopped responding. :-)


-- Rod Adams

Reply via email to