Martin Kealey wrote:
> On Tue, 31 Mar 2009, Jon Lang wrote:
>> Another issue: what happens if conditional code mutates a junction
>> that it filtered? For example:
>>
>> $x = any (-5 .. 5);
>> if $x > 0 { $x++ };
>>
>> At this point, which of the following does $x equal?
>>
>> any(-4 .. 6) # the original junction gets mutated
>> any(-5 .. 0, 2 .. 6) # the filtered part of the original junction
>> gets mutated; the rest is untouched
>> any(2 .. 6) # the filtered part of the original junction gets
>> mutated; the rest is lost
>
> I choose #3.
>
> Reality can only take one path through a conditional; which one depends
> on the one/any/all/none binding of the junction.
>
> Once you've passed the conditional, you have:
>
> one -> single matching value (no longer a junction)
> any -> filtered list
> all -> original junction
> none -> empty (*1)
I'm a bit worried about 'none', for reasons that I'll get to in a moment.
> The "threading" is an implementation detail; the important thing is a
> junction is collection of values and a smart way of rewriting
> expressions that contain them, with special treatment for comparison
> operators (or indeed anything that forces Boolean content):
>
> $x CMP all($y,$z) $x CMP $y && $x CMP $z
> $x CMP one($y,$z) $x CMP $y ^^ $x CMP $z (*2)
> $x CMP none($y,$z) all($x !CMP $y, $x !CMP $z)
> $x CMP any($y,$z) $x !CMP none($y, $x)
>
> $x OP all($y,$z) all( $x OP $y, $x OP $z)
> $x OP any($y,$z) any( $x OP $y, $x OP $z)
> $x OP one($y,$z) one( $x OP $y, $x OP $z)
> $x OP none($y,$z) none($x OP $y, $x OP $z)
>
> -Martin
>
> (*1: An argument could be made that "none" should leave the junction alone,
> the same as "all".)
>
> (*2: I would like to suggest that the semantics of "one" be changed to mean
> "pick one" (randomly) rather than "exactly one". In this respect it
> would be the same as "any" except it wouldn't have the overhead of
> filtering *every* match, just at least one.)
A few thoughts here. First: should autothreading be lazy or eager?
As things stand, it seems to be eager: the moment you pass a junction
into a routine that doesn't ask for a junction in its signature, you
autothread that routine. This has the nice benefit of being easy to
implement (autothread if the parameter doesn't specify 'junction';
don't autothread if it does); but as has been mentioned before, making
life easy on the implementor isn't a primary design goal for Perl. I
submit that autothreading should be lazy.
As I see it, there are currently three things that can be done with a junction:
1. Nothing. Using the "junction as threads" paradigm, you bundle
the threads together and route them through a given part of the
program as a single "rope".
2. Autothreading. You feed each thread through individually, and
rebundle the results on the other side.
3. Sieving. You feed only some of the threads through a decision
point into its guarded region, and rebundle at the end of the guarded
region.
Option 3 raises some additional questions. What do you rebundle at
the end of the guarded region? Just the threads that were passed
through it, or all of the original threads? And what happens if the
program flow gets rerouted inside the guarded region such that it
never comes out the other side?
If I say:
$x = any(-5 .. 5)
if $x > 0 { $x++ }
if $x ~~ (-1 .. 1) { $x *= 2 }
What is $x just before and just after '$x++'? What is $x just before
and just after 'if $x > 0 { $x++ }'? Ditto with '$x *= 2' and 'if $x
< 0 { $x *= 2 }'?
If I say:
$x = any(-5 .. 5)
if $x > 0 { return }
if $x ~~ (-1 .. 1) { doit($x) }
What junction should doit be receiving?
Second:
sub sayit (Str $s) { say $s }
sayit 'S' | 5;
What should happen? Should the junction be autothreaded, and then one
of the threads fail due to a type mismatch? Or does parameter-passing
count as a kind of decision-point, such that you only get the "sayit
'S'" thread?
And what happens with the following?
sayit none('S');
--
Jonathan "Dataweaver" Lang