Re: Tweaking junctions

2010-11-01 Thread Moritz Lenz
On 10/22/2010 06:16 AM, Damian Conway wrote:
 That is, a C$value is an eigenstate of a C$junction if-and-only-if:
 
 $value !~~ Junction$value ~~ $junction

In general this definition makes it impossible to return a list of
eigenstates from the junction. Just think of junctions containing Code
objects. Or anything more complicated than the built-in value types.

 But the C!eigenstates method (as currently defined) does not return
 a list of such eigenstates. Instead it merely returns a partially-flattened
 list of the raw internal values of the junction...which is not (usually) the
 same thing at all.

Right; but afaict it's the only thing that can actually be implemented.
And because it doesn't make all too much sense, it's specced to be private.



Re: Tweaking junctions

2010-11-01 Thread Damian Conway
Moritz wrote:

     $value !~~ Junction    $value ~~ $junction

 In general this definition makes it impossible to return a list of
 eigenstates from the junction. Just think of junctions containing Code
 objects.

Well, that's a deficiency in smartmatching: that Callable ~~ Code doesn't
check for identity between the two objects. Likewise the Regex ~~ Regex
doesn't check for identity. Likewise Range ~~ Range testing for identical
endpoints. Etc. ;-)

The definition of eigenvalues() is supposed to be abstractly
descriptive, not specifically constructive. The idea is simply: any
leaf state inside the junction to which the junction could collapse.

Now the implementation I already provided does currently rely on
smartmatching, but that will be fixed pronto, now that you've kindly
pointed out that smartmatching is...well...broken on several interesting
types of states. :-)


 Right; but afaict it's the only thing that can actually be implemented.
 And because it doesn't make all too much sense, it's specced to be private.

Fine. But please change the name anyway.

If we all agree it's not returning eigenstates, and some of us believe it
*can't* every return eigenstates, then it certainly shouldn't be called
C.eigenstates.

Damian


Re: Tweaking junctions

2010-11-01 Thread Moritz Lenz


On 11/01/2010 12:41 PM, Damian Conway wrote:
 Moritz wrote:
 
 $value !~~ Junction$value ~~ $junction

 In general this definition makes it impossible to return a list of
 eigenstates from the junction. Just think of junctions containing Code
 objects.
 
 Well, that's a deficiency in smartmatching: that Callable ~~ Code doesn't
 check for identity between the two objects. Likewise the Regex ~~ Regex
 doesn't check for identity. Likewise Range ~~ Range testing for identical
 endpoints. Etc. ;-)

Sorry, I disagree. It's exactly what smartmatching was designed to be.
If you don't want that kind of behaviour, use infix:eqv or infix:===
instead.

 The definition of eigenvalues() is supposed to be abstractly
 descriptive, not specifically constructive. The idea is simply: any
 leaf state inside the junction to which the junction could collapse.

Junctions only collapse to Bool::True or Bool::False.

So an attempt to fix your definition could be

'any leaf state inside the junction, which makes the junction collapse
to True if compared to the junction as a whole'

but begs for a more concrete comparison rule. For which, IMHO
smartmatching would be nice, since I mostly use junctions for
smartmatching. Which brings us into the dilemma I mentioned before.


 Right; but afaict it's the only thing that can actually be implemented.
 And because it doesn't make all too much sense, it's specced to be private.
 
 Fine. But please change the name anyway.
 
 If we all agree it's not returning eigenstates, and some of us believe it
 *can't* every return eigenstates, then it certainly shouldn't be called
 C.eigenstates.

Agreed.

Cheers,
Moritz


Re: Tweaking junctions

2010-11-01 Thread Moritz Lenz
Food for thought, a few non-junction solutions:

On 10/22/2010 06:16 AM, Damian Conway wrote:
 # Find the list of common elements in two lists...
 sub intersection (@list1, @list2) {
 (any(@list1)  any(@list2).eigenstates;
 }

sub intersection(@list1, @list2) {
uniq gather for @list1 X @list2 - $a, $b {
 take $a if $a eqv $b
}
}

or

sub interseection(@list1, @list2) {
   (@list1 X= @list2).grep({ .key eqv .value}).key.uniq
}

Admittedly it's not as declarative, but it's explicit about the
comparison used (which is a plus, in my eyes).

If you want to use eq or ===, hash based solutions come to mind too.

 # Find the factors of a number...
 sub factors (Num $n) {
 ( $n/any(1..$n) ).eigenstates.grep({ $^q.Int == $q });
 }


sub factors($n) {
($n X/ 1..$n).grep: { .Int == $_ }
}

or

sub factors($n) {
   (1..$n).grep: { %n %% $_ }
}

 # Check for an unacceptable password, and list all when warning...
 constant UNACCEPTABLE = any  Godel Escher Bart etc... ;
 
 if $passwd ~~ UNACCEPTABLE {
 say Unacceptable password. Don't use any of these:;
 say UNACCEPTABLE.eigenstates¬».fmt(\t%s\n);
 }

constant UNACCETABLE = Godel Escher Bach;

if $passwd ~~ any UNCACCEPTABLE {
say Unacceptable password. Don't use any of these:;
say UNACCEPTABLE».fmt(\t%s\n);
}


Re: Tweaking junctions

2010-11-01 Thread Buddha Buck
On Mon, Nov 1, 2010 at 7:24 AM, Moritz Lenz mor...@faui2k3.org wrote:
 On 10/22/2010 06:16 AM, Damian Conway wrote:
 That is, a C$value is an eigenstate of a C$junction if-and-only-if:

     $value !~~ Junction    $value ~~ $junction

 In general this definition makes it impossible to return a list of
 eigenstates from the junction. Just think of junctions containing Code
 objects. Or anything more complicated than the built-in value types.

[Originally sent to Moritz alone because of Reply not sending to the list]


Is it too late in this discussion to point out that, in non-perl
usage, eigenstates are associated with the operator, not with the
value fed into the operator?

[Added at Moritz request]

In linear algebra, eigenvectors and eigenvalues are non-trivial
solutions to the equation Ax=λx, where x is a vector in a vector
space, A is a operator (a function from a vector space to itself) and
λ is a member of the field the vector space is defined over.  For a
given operator A, only certain values of λ allow that equation to be
solved, and those values are called the eigenvalues for A.  Also,
for a given operator A, only certain vectors x will solve the
equation, and those vectors are called eigenvectors.  It should also
be clear that different values of λ work with different sets of
vectors x  (the solutions to Ax = ax and Ax=bx are different if a !=
b), so it's typical to talk about the eigenvectors of A associated
with a given eigenvalue λ.

Since A is linear, if Ax=λx  and Ay=λy, then A(ax) = a(Ax) = a(λx) =
λ(ax) and A(x+y)=Ax+Ay=λx+λy=λ(x+y), so fir a given eigenvalue λ,
there are typically multitudes of eigenvectors which form a vector
space of their own.  Eigenvectors for different eigenvalues are
orthogonal, and any eigenvector can be scaled to be a unit
eigenvector.  If an operator has a full set of eigenvalues, one can
pick a set of unit eigenvectors to act as a natural orthonormal basis
for the operator.  If operator A has three eigenvalues a, b, c, and
three unit eigenvectors x, y, z, such that Ax=ax, Ay=by, and Az=cz,
then if w = dx+ey+fz, Aw = a(dx)+b(ey)+c(fz), which is really easy to
compute.

In quantum mechanics, especially the Heisenberg matrix formulation
(but by analogy, also every other formulation, including wave
mechanics), quantum states are represented by vectors in a complex
vector space, and vectors which differ by a real-valued scaling factor
are generally considered equivalent.  Transformations (i.e., anything
which modifies the quantum state of the system, including but not
limited to the passage of time) are represented by (unitary) operators
on the state space.  (Unitary in this case means that the norm of Ax
is the same as the norm of x, for all x.)  The standard notation is a
bit odd, where the 'ket' |x represents a system in state x (and
therefore |x+y a state in a superposition of x and y), The 'bra' x|
is the complement of the ket |x, and can be multiplied by a ket to
get a braket x|y which represents the probability that a system in
state y is also in state x.  |x is, naturally, usually normalized
such that x|x = 1.  Operators act on kets and return kets, so A|x
is the braket notation way of writing the linear algebra Ax.
Naturally, that means that y|A|x is the probability that a system
that starts in state x will be in state y after the transform A.

Since A is a linear operator, it has eigenvalues and eigenvectors.  In
the quantum mechanical world, where vectors represent states, the
eigenvectors are called eigenstates.  Eigenstates |i, |j of an
operator A have the property that i|A|i = j|A|j = 1, but i|A|j =
0 (informally, if you start in an eigenstate of A, then the transform
leaves you unchanged).  However, A|i+j = |ai+bj, so A can change the
nature of a superposition of states.  i|i+j = 1/2, j|i+j = 1/2,
but i|A|i+j = a/(a+b), j|A|i+j = b/(a+b).

Schrodinger's Wave Equation, in matrix notation, is of the form Hx=Ex,
where H is the Hamiltonian operator of the system, and E is the
energy of the system, so the only allowed solutions of the wave
equations are for energy levels E which are eigenvalues of H,and for
quantum states which are eigenstates of H.  Similar equations exist
for virtually every observable, so the only allowable momenta are
the eigenvalues or eigenstates of the momentum operator, the only
allowable positions are the eigenvalues or eigenstates of the position
operator, etc.

So asking for the eigenstates of a quantum superposition is asking the
wrong object for the property.


Re: Tweaking junctions

2010-11-01 Thread Dave Whipp

Buddha Buck wrote:

Is it too late in this discussion to point out that, in non-perl
usage, eigenstates are associated with the operator, not with the
value fed into the operator?

[cut]

So asking for the eigenstates of a quantum superposition is asking the
wrong object for the property.


Probably is, yes :(. I argued the same thing a couple of years back 
(http://dave.whipp.name/sw/perl6/perl6_xmas_2008.html -- wow, p6/rakudo 
has advanced a lot since then!) when I suggested bra-ket notation for 
extracting the values of a junction:


  $player_value = max | 4..21 |==| $player_value_junc |

(in this case, the value of a blackjack hand). Since then, I simplified 
this idea to use a more perl6ish meta-operator:


  $player_value = max 4..21 G== $player_value_junc

My current belief is that it is likely that there'll eventually be 
sufficient core functionality that I'll be able to implement something 
like this as a module. So I don't push it except when someone else 
starts a thread about the values of a junction :).



Dave.


Re: Tweaking junctions

2010-10-29 Thread Martin D Kealey
On Thu, 28 Oct 2010, Damian Conway wrote:
 The apparent paradox ... is due to the assumption (employed in the
 second interpretation) that  is identical to !=. Certainly that is
 true for simple scalar numbers, but not always for vector types such
 as tuples, sets, bags, complex numbers...or junctions.

 That doesn't make either  or != intrinsically invalid on vector types
 (though they obviously are inappropriate for *some* vector types); it just
 means you can't reasonably treat the two operators as universally
 interchangeable, just because they sometimes are.

Well, I think returning or throwing an Unordered exception would be
the appropriate way to handle those, both for complex numbers and for
junctions.

Anyone who thinks they're dealing with real numbers will reasonably
expect  and != to be the same, and a junction can masquerade as
anything (within each thread), including a real number.

And what about when that difference is wrapped up inside a function? In
other words, what's wrong when I expect the following two snippets to
work the same way?

A:

sub anything_is_broken($subject) {
grep { ! .test() } $subject.parts()
}

if anything_is_broken($subject) {
fail($subject)
}
else {
pass($subject)
}

B:

sub everything_is_working($subject) {
! grep { ! .test() } $subject.parts()
}

if everything_is_working($subject) {
pass($subject)
}
else {
fail($subject)
}

Why should it make a difference whether $subject is a junction?

 In summary, the problem here seems to be that, algebraically,
 junctions don't behave exactly like non-junctions. Which is true, but no
 more a problem than the fact that, algebraically, complex numbers don't
 behave exactly like non-complex numbers, or that sets don't behave
 exactly like non-sets, or that Rats don't behave exactly like Nums,
 which don't behave exactly like Ints, which don't behave exactly like
 ints either.

When you're talking about built-in operators, that's plausible, because
by looking for ! in the operator name there are ways to
DWIM-or-throw-an-exception.

That's not true for user-defined functions, so I think the real problem
is that the parallelizing of the expression that contains a junction may
not be obvious at the point where it happens.

Hmmm  maybe one way to improve that might be to say that you can't
put a junction into an untyped scalar, or indeed in any variable that
isn't explicitly marked as this thing might contain a junction. That
would apply, as now, to function parameters and returns, but also to
variables and aggregate members; indeed, *everywhere*.

 And, of course, that's why Perl 6 has strong typing. So that, when
 these differences in behaviour do matter, we can specify what kind(s)
 of data we want to allow in particular variables, parameters or return
 slots...and thereby prevent unexpected kinds of data from sneaking in
 and violating (un)reasonable expectations or inducing (apparent)
 paradoxes. :-)

I don't think strong typing is enough, because we explicitly mask the
application of type constraints by autothreading. Each thread sees a
thing with the type it expects, but the problem comes when the threads
are recombined; the result often won't be what's expected.

Don't get me wrong, I think Junctions are a really clever way of writing
concise conditional expressions, but I think algebraic consistency is
more important than clever conciseness.

-Martin


Re: Tweaking junctions

2010-10-29 Thread Damian Conway
Martin D Kealey suggested:

 Well, I think returning or throwing an Unordered exception would be
 the appropriate way to handle those, both for complex numbers and for
 junctions.

For complex numbers that might be true, because the order relationship
between two complex numbers isn't expressible in-band.

But for junctions, the relationship of sometimes , somtimes = is
entirely expressible. It's just: any(True, False).


 And what about when that difference is wrapped up inside a function? In
 other words, what's wrong when I expect the following two snippets to
 work the same way?

sub anything_is_broken($subject) {
grep { ! .test() } $subject.parts()
}


sub everything_is_working($subject) {
! grep { ! .test() } $subject.parts()
}

 Why should it make a difference whether $subject is a junction?

Because, although the two subroutines seem like they're complementary,
they actually only partition the universe when the universe is strictly
one-dimensional. And sometimes not even then.

For example, here's a *non-junctive* scalar subject for which the two
don't provide consistent answers either:

class Part {
has $.value;
method test { $.value != 0 }
}

class Subject {
has Part @.parts;
method parts { @.parts.pick(2) }
}

my Subject $subject .= new(0..9);

say anything_is_broken($subject);# 0 (because .parts picked 3 and 7)
say everything_is_working($subject); # 0 (because .parts picked 9 and 0)

In other words, it isn't the junctive-ness that creates unexpected
behaviour, it's the assumption that every scalar works the same way.


 That's not true for user-defined functions, so I think the real problem
 is that the parallelizing of the expression that contains a junction may
 not be obvious at the point where it happens.

But that's not a unique property of junctions; that not obviousness
is equally true of any scalar that, for example, simply overloads .Num
or .Str or .Bool.

For instance:

if $result { say $result }

can easily print 0, which is not obvious, but is still both correct
and useful (when, for example, $result the result of a call to Csystem).


 Hmmm  maybe one way to improve that might be to say that you can't
 put a junction into an untyped scalar, or indeed in any variable that
 isn't explicitly marked as this thing might contain a junction. That
 would apply, as now, to function parameters and returns, but also to
 variables and aggregate members; indeed, *everywhere*.

But junctions are an intrinsic part of Perl 6. So it's unreasonable to
*not* expect them. And if you want to not expect them, you can just mark
your variables that way, with (ironically):

my $subject where none(Junction);

Besides, are you also going to extend this segregation of junctions to
not allow C0 but true in untyped scalars either? Because how else will
you avoid the non-obviousness of:

 if $result { say $result }

???


 I don't think strong typing is enough, because we explicitly mask the
 application of type constraints by autothreading. Each thread sees a
 thing with the type it expects, but the problem comes when the threads
 are recombined; the result often won't be what's expected.

Huh? If the variables are strongly typed as non-junctive, a junction
will never be able sneak past into or out-of an autothreading.


 Don't get me wrong, I think Junctions are a really clever way of
 writing concise conditional expressions, but I think algebraic
 consistency is more important than clever conciseness.

Aha. I see that we mean different things when we use the term algebraic
consistency. You seem to want all algebras to be universally
consistent; I want each algebra to be internally consistent. Or to put
it another way, you appear to want:

A given operator or function does one consistent thing
(regardless of the specific types of its operands)

whereas I want:

A given operator or function does one thing
(consistent with the specific types of its operands)

In other words, you seem to be arguing for monomorphism, whereas I'm
definitely arguing for polymorphism. Neither is inherently better, but
one is inherently more powerful. While I deeply respect your
position, I'm going to keep arguing for that more powerful alternative.

Damian


Re: Tweaking junctions

2010-10-28 Thread Damian Conway
Martin D Kealey asked:

 Or do we not invert junctions, and run the risk of unexpected
 action-at-a-distance instead?

I think our current approach is correct. That is: we invert
junctions on operators that are themselves intrinsically inverted
(such as !=, !~~, !), but do not invert on those that are not
(such as ==, ~~, =). Or rather, we *never* invert junctions at all, but
merely honour the standard semantics of the prefix:! metaoperator:
hoisting the negation outside the entire operation and applying it
once the underlying operation is complete.

The apparent paradox you demonstrated with the two interpretations of
C$foo  ($bar | $zot) is due to the assumption (employed in
the second interpretation) that  is identical to !=. Certainly that is
true for simple scalar numbers, but not always for vector types such as
tuples, sets, bags, complex numbers...or junctions. That doesn't make
either  or != intrinsically invalid on vector types (though they
obviously are inappropriate for *some* vector types); it just means you
can't reasonably treat the two operators as universally interchangeable,
just because they sometimes are.

In summary, the problem here seems to be that, algebraically,
junctions don't behave exactly like non-junctions. Which is true, but no
more a problem than the fact that, algebraically, complex numbers don't
behave exactly like non-complex numbers, or that sets don't behave
exactly like non-sets, or that Rats don't behave exactly like Nums,
which don't behave exactly like Ints, which don't behave exactly like
ints either.

And, of course, that's why Perl 6 has strong typing. So that, when these
differences in behaviour do matter, we can specify what kind(s) of data
we want to allow in particular variables, parameters or return
slots...and thereby prevent unexpected kinds of data from sneaking in and
violating (un)reasonable expectations or inducing (apparent) paradoxes. :-)


With regard to your other point:

 If it's about parallel data handling, then we have to be prepared to
 (notionally) fork the entire rest of the runtime, even as far as
 having a definition of what return value the parent process sees (from
 exit) when those threads are implicitly collapsed at termination.

That's certainly true, although junctions are supposed to guarantee
to coalesce all the threads they may generate back into a single superimposed
result back in the originating thread.

The problem only arises if an operation or subroutine that has been
junctively threaded terminates without returning. But that's just
having a side-effect, which we already know is inappropriate for
junctions (and hyperoperators, and autothreaded loops, and pretty much
any other kind of parallel construct).

Damian


Re: Tweaking junctions

2010-10-28 Thread Darren Duncan

Damian Conway wrote:

If it's about parallel data handling, then we have to be prepared to
(notionally) fork the entire rest of the runtime, even as far as
having a definition of what return value the parent process sees (from
exit) when those threads are implicitly collapsed at termination.


That's certainly true, although junctions are supposed to guarantee
to coalesce all the threads they may generate back into a single superimposed
result back in the originating thread.

The problem only arises if an operation or subroutine that has been
junctively threaded terminates without returning. But that's just
having a side-effect, which we already know is inappropriate for
junctions (and hyperoperators, and autothreaded loops, and pretty much
any other kind of parallel construct).


Could thread termination without a return reasonably be treated as another way 
of saying returns nothing or alternately returns an empty junction (a junction 
ranging over zero values)?  Or would that instead better be treated as an error 
such that returning nothing should have been done explicitly? -- Darren Duncan


Re: Tweaking junctions

2010-10-27 Thread Martin D Kealey

I have to admit to feeling uneasy about the whole action-at-a-distance
effect that junctions are capable of producing. They sit around pretending
to be a scalar, only to pop up and wreak havoc with ones expectations of
linearity when you're not expecting it.

That unexpected-action-at-a-distance is somewhat mitigated by autothreading
functions where the junction is presented as a direct parameter, but being
able to defer a junction by putting it inside an aggregate seems like asking
for trouble unless we make sure that it behaves as much like an ordinary
scalar as possible when it does finally get collapsed.

I think we need to decide whether junctions are just about flow control, or
are more generalized parallel data handling, typified as a way of handling
sets.

If it's about parallel data handling, then we have to be prepared to
(notionally) fork the entire rest of the runtime, even as far as having a
definition of what return value the parent process sees (from exit) when
those threads are implicitly collapsed at termination. And deciding what
happens when, in the process of autothreading junction A, you wind up
collapsing junction B in different ways (including perhaps not collapsing
it)? Right now I don't think we're up for all that.

For the sake of flow control, do we have a formal algebra of how we apply
distributive rules so that all the elements of the resulting junction are
booleans and the result of the collapse is obvious?

In the simple cases it's (supposedly) obvious:
$foo == ($bar | $zot)   === ($foo == $bar) | ($foo == $zot)

But what about:
$foo != ($bar | $zot)   === not($foo == ($bar | $zot))
=== not(($foo == $bar) | ($foo == $zot))
=== (not($foo == $bar))  (not($foo == 
$zot))
=== ($foo != $bar)  ($foo != $zot)

Moreover, what about:
$foo  ($bar | $zot)=== ($foo  $bar) | ($foo  $zot)
versus:
$foo  ($bar | $zot)=== not($foo = ($bar | $zot))
=== not(($foo = $bar) | ($foo = $zot))
=== (not($foo = $bar))  (not($foot = 
$zot))
=== ($foo  $bar)  ($foo  $zot)

In short, in order to avoid unexpected action at a distance, it's logical to
invert the junction type, but in doing so you hit some very nasty corner
cases. How do you know whether a function is saying X has property Y or
X does not have property ~Y ? Which of Y or ~Y are we talking about?

It seems fair enough to infer that equality comparison is Y rather than
~Y, but any other sort of comparison is fraught.

This leads me to the conclusion that collapsing a junction over an ordered
comparison should fail in the same way that an ordered comparison involving
complex numbers or vectors should fail (or more generally, an ordered
comparison of any aggregate should fail unless the aggregate type defines some
sensible ordering; there should be no default).

Indeed, the whole notion of autothreading a junction over an arbitrary
function (to produce a boolean that can be used for flow control) starts to
sound fishy: how do we decide whether a given function should be treated
like ==, where the distributive rule produces the same junction type, or
like !=, where the distributive rule produces the inverse junction type?

Or do we not invert junctions, and run the risk of unexpected
action-at-a-distance instead?

-Martin


Re: Tweaking junctions

2010-10-26 Thread Damian Conway
Jon Lang wrote:

 Personally, I don't think that it should be a public method: one thing
 about junctions is that you can use them interchangeably with ordinary
 scalars; giving them a public method breaks that.  In particular, code
 that makes use of a Junction public method would break if you were to
 hand it a non-Junction.

On the other hand, I would argue that, because non-junctive scalars are
just an (uninteresting ;-) special degenerate case of junctions, they
should have a public .eigenvalues() too!  It would, of course, just return
their uninteresting degenerate special-case scalar value.

Alternatively, I would note that Perl 6 already provides a perfectly
good way to handle this issue. If you're calling $someval.eigenvalues(),
you're inherently assuming that you're calling it on a Junction. If
there's any possibility that what you're calling it on *isn't* a
junction, then you should either be unsurprised to get the exception that will
be thrown, or else you should explicitly cater to the possibility with:

 my @values = $val.?eigenvalues;

or perhaps:

 my @values = $val.?eigenvalues // $val;

Although, if that second form is to become the standard safe approach,
that argues to me that non-junctions ought to have a .eigenvalues() too,
so that the first alternative above just DWIMs.


BTW, given Larry's recent clarification about Sets producing a list of
their keys in list context, I have absolutely no objection to
.eigenvalues() returning a Set, rather than a List. Indeed, I think it
would be even more valuable that way.

Damian


Re: Tweaking junctions

2010-10-26 Thread Todd Olson

On 2010-Oct-25, at 15:14, Damian Conway wrote:

 Yes, Ted Z. pointed out to me that, as the name of this construct,
 every has ambiguity and synonym issues. Other possibilities are:
 
select(@values)  one(3..7)
those(@values)  one(3..7)
whichever(@values)  one(3..7)
itemize(@values)  one(3..7)
extract(@values)  one(3..7)
 
 ...of which, only Cselect really seems a good alternative.
 
 Any other suggestions most welcome!

Applying a slightly more stringent test example,
the above terms, plus a few new suggestions,
separates in to two groups

  these work for me

@nv = those(@values)  one(3..7)
@nv = only(@values)  one(3..7)
@nv = solely(@values)  one(3..7)
@nv = exclusively(@values)  one(3..7)
@nv = whichever(@values)  one(3..7)

  these do not work for me

@nv = select(@values)  one(3..7)
@nv = extract(@values)  one(3..7)
@nv = isolate(@values)  one(3..7)
@nv = locate(@values)  one(3..7)
@nv = itemize(@values)  one(3..7)


It is tempting to use

@nv = sift(@values)  one(3..7)
@nv = winnow(@values)  one(3..7)

however, like 'filter' it is confusing what they focus attention on.
Often they focus on what is being discarded
   To winnow the chaff from the grain
yet sometimes they focus on what is being retained
   it's difficult to winnow out the truth
   it's difficult to sift out the truth

I wonder if some times we might desire what is to be discarded,
that is the complement of the outcome this conversation started with.

(@keep, @discard) = filter(@values)  one(3..7)
(@grain, @chaff)  = winnow(@values)  one(3..7)
(@truth, @lies)   = sift(@values)  one(3..7)


Regards,
Todd


Re: Tweaking junctions

2010-10-25 Thread Ben Goldberg
On Oct 22, 6:41 pm, dam...@conway.org (Damian Conway) wrote:
 Dave Whipp wrote:
  When this issue has been raised in the past, the response has been that
  junctions are not really intended to be useful outside of the narrow purpose
  for which they were introduced.

 Hmm. There are intentions, and then there are intentions. I know
 what I intended when I invented the original idea, and it wasn't just the 
 narrow
 purpose for which they were added to Perl 6. :-)

  Problem 2 could be solved by defining a new (and public!)
  C.eigenstates method in the Junction class. [...]

  I think that you're proposed solution is a bit too specific:

 That's because I didn't explain Part B of my nefarious plan! namely
 that, if you'd only give me proper eigenstates, I'd give you an even
 nicer alternative.

 I actually think that the meta doesn't belong on the operator at all
 (though I have no problem with that idea in itself).

 Instead, I think the meta should be placed on the data (which, of
 course, is what any(), all(), one(), and none() already do).

 So I'm going to go on to propose that we create a fifth class of
 Junction: the transjunction, with corresponding keyword Cevery.
[snip]

I'm probably missing something, but wouldn't it have been easier to
write that module by using eval STRING to create all of those infix
operators?

Start with a list of the names of the operators, generate a string
containing all four argument variations for each operator, then eval
it.



Re: Tweaking junctions

2010-10-25 Thread Damian Conway
Ben Goldberg asked:

 I'm probably missing something, but wouldn't it have been easier to
 write that module by using eval STRING to create all of those infix
 operators?

Sure. But the module is already slow to start up. I was concerned
that it would get even slower with an embedded eval. But, in the
name of maintainability, I probably should benchmark it both ways.

Thanks for pointing that out, Ben.

Damian


Re: Tweaking junctions

2010-10-25 Thread Dave Whipp

Damian Conway wrote:


So I'm going to go on to propose that we create a fifth class of
Junction: the transjunction, with corresponding keyword Cevery.

[...]

say (^10 G[] one(3,7));

3 4 5 6


which could also be:

say every(^10)  one(3,7);
# Every value up to 10 that's greater than 3 or 7 but not both

[...]

I just think those all read much better than the (otherwise excellent)
meta-operator. In much the same way that the existing junctive types
read better than their functional or operator-oriented alternatives.


I think that the two proposals are equivalent, in the sense that either 
can be trivially implemented using the other. So it is indeed a question 
of which one reads better and fits in better. And I agree, your Cevery 
proposal does read better (at least to an English speaker).


However, I am a little concerned that the transjunction magically 
changes an operator that returns a Boolean value into one that returns a 
list. If the usage of a transjuction is non-local to its creation then 
this could result in surprises, and hence frustrating debugging sessions.


If I wanted to write intentionally confusing code (which sometimes 
happens due to carelessness) then I might take advantage of the fact 
that Cevery is, in English, a synonym for Call, not Cany:


  if every(@values)  one(3..7) {...}




I'd like these in the core language (for performance and universal
accessibility), but if not, I already have a nearly-complete
implementation of a module implementing them, which runs successfully on
the current release of Rakudo*. I append said model for your amusement
(and suggestions!).


++

Dave.


Re: Tweaking junctions

2010-10-25 Thread Damian Conway
Dave Whipp noted:

 I think that the two proposals are equivalent, in the sense that either can
 be trivially implemented using the other.

Agreed.


 However, I am a little concerned that the transjunction magically changes
 an operator that returns a Boolean value into one that returns a list.

Technically, it turns the operator into one that returns a transjunction.

The surprise occurs because tranjunctions self-eigenvalue in a list context.
That's a huge convenience in direct usages, but not an essential component
of the proposal if indeed it proves too surprising in indirect usages.

However, if we did lose that feature then usages like:

say eigenvalues every(@number)  one(3,7);

sacrifices more than a little of the construct's original appeal, I think.


 If I wanted to write intentionally confusing code (which sometimes happens
 due to carelessness) then I might take advantage of the fact that Cevery
 is, in English, a synonym for Call, not Cany:

  if every(@values)  one(3..7) {...}

Yes, Ted Z. pointed out to me that, as the name of this construct,
every has ambiguity and synonym issues. Other possibilities are:

select(@values)  one(3..7)
those(@values)  one(3..7)
whichever(@values)  one(3..7)
itemize(@values)  one(3..7)
extract(@values)  one(3..7)

...of which, only Cselect really seems a good alternative.

Any other suggestions most welcome!

Damian


Re: Tweaking junctions

2010-10-25 Thread Dave Whipp

Damian Conway wrote:


Yes, Ted Z. pointed out to me that, as the name of this construct,
every has ambiguity and synonym issues. Other possibilities are:

select(@values)  one(3..7)
those(@values)  one(3..7)
whichever(@values)  one(3..7)
itemize(@values)  one(3..7)
extract(@values)  one(3..7)

...of which, only Cselect really seems a good alternative.

Any other suggestions most welcome!


My suggestion is, of course, to move it to the operator:

  @values G one(3..7)

which has a pleasing (to my mind) symmetry with Perl6-isms such as

  @values X* 2


Failing that, perhaps Cfilter might work (though I always find myself 
wanting to qualify a filter as either filter-in or filter-out).


Re: Tweaking junctions

2010-10-23 Thread Brandon S Allbery KF8NH
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On 10/22/10 13:00 , Dave Whipp wrote:
 Damian Conway wrote:
 I've been thinking about junctions, and I believe we may need a small
 tweak to (at least) the jargon in one part of the specification.
 
 When this issue has been raised in the past, the response has been that
 junctions are not really intended to be useful outside of the narrow purpose
 for which they were introduced.

It occurs to me:  If their purpose is that narrow, why are they wasting
conceptual space in the core language?

- -- 
brandon s. allbery [linux,solaris,freebsd,perl]  allb...@kf8nh.com
system administrator  [openafs,heimdal,too many hats]  allb...@ece.cmu.edu
electrical and computer engineering, carnegie mellon university  KF8NH
-BEGIN PGP SIGNATURE-
Version: GnuPG v2.0.10 (Darwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkzC5gsACgkQIn7hlCsL25Wp8ACbBzcg2kACC/hmtTD1GUGe2lD2
2ucAmgNSPb5F6T3SqqHMvvG7UzFR9M3D
=1x5F
-END PGP SIGNATURE-


Re: Tweaking junctions

2010-10-23 Thread Damian Conway
Brandon mused:

 It occurs to me:  If their purpose is that narrow, why are they wasting
 conceptual space in the core language?

Well, mainly because their purpose isn't narrow at all: it's parallelized data
comparisons (all(@values)  $threshold), and multiway comparisons
(all(@values) ~~ any(@ranges)), and distributed sub calls on a
set of arguments (foo(any @alternatives), and subroutine call
parallelism (foo  bar)($arg), and type unions (my Wax|Polish $shimmer),
and type intersections (my $coefficient where Num  0..1), and parallel
lookup of arrays and hashes ($name ~~ %known_aliases{any $suspect}),
and multiway existence checks (if any %f...@args} :exists), and
convenient multiple file tests ($fh ~~ :r  :w  :!x), and overlapping
or exhaustive matches (my $results = m:ex/foo/), and complex matching
logic expressed declaratively (my $is_valid = Num  {$_0} | Str  /zero|one/).

And, of course, they're in the core because there's no point in having
that much power and usefulness if it's not fast too.

Damian


Re: Tweaking junctions

2010-10-23 Thread yary
In general I like where this is going but need a little hand holding
here- I'm not an expert on junctions or anything perl6-

 So I'm going to go on to propose that we create a fifth class of
 Junction: the transjunction, with corresponding keyword Cevery.

It seems that by these definitions every isn't quite a junction-

every(@list)  comparision-op  value
to mean ...
   grep  * comparision-op value,  @list;

You'll need to specify but not necessarily in the same order if you
want junctive autothreading to work on every as it does with other
junctions. In which case it should probably be returning a junction
and not an ordered list.

Which reminds me, .eigenvalues strictly speaking is a set and not a
list. !eigenstates can be whatever the internal representation is...
not that I've checked the synopsis on that...

And while I like the cleanliness of the every expressions I'm still
having trouble seeing why every should behave differently from
any, all. Maybe every isn't a junction? Maybe junctions in
general need to behave a little differently when being compared
against then they do now, so the need for every goes away?


Re: Tweaking junctions

2010-10-23 Thread Damian Conway
 In general I like where this is going but need a little hand holding
 here- I'm not an expert on junctions or anything perl6-

 So I'm going to go on to propose that we create a fifth class of
 Junction: the transjunction, with corresponding keyword Cevery.

 It seems that by these definitions every isn't quite a junction-

It's an unordered collection of values that can be used like a single
value, is parallelizable, and has an intrinsic associated operation.
That's pretty much a junction. The only difference is that the
associated operation is (in a sense) Cgrep, rather than C,
C||, C^^, or C!


 You'll need to specify but not necessarily in the same order if you
 want junctive autothreading to work on every as it does with other
 junctions.

You're quite right. I should have been more specific about that.
And, yes, I certainly do want to leave open the potential for parallel
evaluation.


 In which case it should probably be returning a junction
 and not an ordered list.

If you look at the implementation I appended, any comparison
on a transjunction returns a transjunction. But it turns out to be
much more useful if they also collapse to a list, which is why I
implemented them as a role added to arrays/lists.


 Which reminds me, .eigenvalues strictly speaking is a set and not a
 list.

Sure, but again, it's much more useful as a list. ;-)


 And while I like the cleanliness of the every expressions I'm still
 having trouble seeing why every should behave differently from
 any, all. Maybe every isn't a junction?

Maybe not, in the strictest sense. But it has many of the same characteristics
and is extremely useful in many of the same kinds of ways as a duck^Wjunction.


 Maybe junctions in general need to behave a little differently when
 being compared against then they do now, so the need for every
 goes away?

Interestingly, that was how they were originally defined (back when they
were called Quantum::Superpositions). Comparing a superposition
produced a superposition of just those values for which the comparison
was true.

But I agree with Larry's decision to make junctions behave normally wrt
comparisons. They're much easier to understand the way they are now.

I am merely trying to reintroduce the useful extra concept of a
collection of numbers that filters under comparisons. But if people
aren't comfortable, I'm happy to leave it as a module (especially since
it's already written).

I would hate this (very worthwhile) discussion to distract from the key
point of the original post: namely, that the private C!eigenstates is
misnamed, and a public C.eigenvalues is missing.

Damian


Re: Tweaking junctions

2010-10-22 Thread Dave Whipp

Damian Conway wrote:

I've been thinking about junctions, and I believe we may need a small
tweak to (at least) the jargon in one part of the specification.


When this issue has been raised in the past, the response has been that 
junctions are not really intended to be useful outside of the narrow 
purpose for which they were introduced.



Problem 2 could be solved by defining a new (and public!)
C.eigenstates method in the Junction class. [...]


I think that you're proposed solution is a bit too specific: it assumes 
that when you say eigenstates, what you really mean is the set of 
values that would compare equal to. I have no problem with that 
concept, expect that I think that it would be better realized as a 
meta-operator -- I previously proposed G[op] as that operator (G for 
grep) -- to reinforce the idea that you only get to peer into a junction 
if you state the operator.


 sub factors (Num $n) {
 ( $n/any(1..$n) ).eigenstates.grep({ $^q.Int == $q });
 }

could be:

sub factors (num $n) { ^$n G[==] $n/any(1..$n) }


if $passwd ~~ UNACCEPTABLE {
say Unacceptable password. Don't use any of these:;
say UNACCEPTABLE.eigenstates¬».fmt(\t%s\n);
}


Could be

  if $passwd ~~ UNACCEPTABLE {
  say Unacceptable password. Don't use any of these:;
  say (::Str G[eq] UNACCEPTABLE)».fmt(\t%s\n)
  }

And, of course:

  method eigenstates( Junction $v : ) {
::Any G=== $v
  }

Operations other than equality could be used:

say (^10 G[] one(3,7));
 3 4 5 6



I suggest a meta-op instead of simply using the grep method to 
strongly imply that the implementation would need to be analytic in nature.


Re: Tweaking junctions

2010-10-22 Thread Damian Conway
Dave Whipp wrote:

 When this issue has been raised in the past, the response has been that
 junctions are not really intended to be useful outside of the narrow purpose
 for which they were introduced.

Hmm. There are intentions, and then there are intentions. I know
what I intended when I invented the original idea, and it wasn't just the narrow
purpose for which they were added to Perl 6. :-)


 Problem 2 could be solved by defining a new (and public!)
 C.eigenstates method in the Junction class. [...]

 I think that you're proposed solution is a bit too specific:

That's because I didn't explain Part B of my nefarious plan! namely
that, if you'd only give me proper eigenstates, I'd give you an even
nicer alternative.

I actually think that the meta doesn't belong on the operator at all
(though I have no problem with that idea in itself).

Instead, I think the meta should be placed on the data (which, of
course, is what any(), all(), one(), and none() already do).

So I'm going to go on to propose that we create a fifth class of
Junction: the transjunction, with corresponding keyword Cevery.

Then we define:

every(@list)  comparision-op  value
every($junction) comparision-op  value

to mean repectively:

grep  * comparision-op value,  @list;
grep  * comparision-op value,  $junction.eigenstates;

as well as the reverses:

value comparision-op every(@list)
value comparision-op every($junction)

to mean respectively:

grep  value comparision-op *,  @list;
grep  value comparision-op *,  $junction.eigenstates;


So then we get:

 sub factors (Num $n) { ( $n/any(1..$n) ).eigenstates.grep({ $^q.Int == 
 $q }); }

 [which] could be:

 sub factors (num $n) { ^$n G[==] $n/any(1..$n) }

could instead be:

sub factors (Num $n) {
 every( $n/any(1..$n) ) ~~ { $^q.Int == $q });
 # Every quotient of N divided by any lesser integer, where
the quotient is also an integer
}


and:

say UNACCEPTABLE.eigenstates¬».fmt(\t%s\n);

 [which] could be

  say (::Str G[eq] UNACCEPTABLE)».fmt(\t%s\n)

could also be:

say (every(UNACCEPTABLE) ~~ ::Str)».fmt(\t%s\n)
# Everything unacceptable that's a string, formatted as follows...


 Operations other than equality could be used:

 say (^10 G[] one(3,7));
 3 4 5 6

which could also be:

say every(^10)  one(3,7);
# Every value up to 10 that's greater than 3 or 7 but not both

And so on:

say every(factor_of($x)  factor_of($y))  10;
# Every common factor of both X and Y that's greater than 10

say every(@coefficient) ~~ 0..1;
# Every coefficient in the range 0 to 1

say every(@string) ~~ /target/;
# Every string that matches the target pattern

I just think those all read much better than the (otherwise excellent)
meta-operator. In much the same way that the existing junctive types
read better than their functional or operator-oriented alternatives.

I'd like these in the core language (for performance and universal
accessibility), but if not, I already have a nearly-complete
implementation of a module implementing them, which runs successfully on
the current release of Rakudo*. I append said model for your amusement
(and suggestions!).

Damian

-cut--cut--cut--cut--cut--cut--cut--cut-

module Transjunctions;

# Add missing public method (and equivalent function) to junctions
#  Call them .eigenvalues(), so as not to clash with existing misnamed
!eigenstates()...
use MONKEY_TYPING;
augment class Junction {
method eigenvalues (Junction $j:) {
my @values = $j.eigenstates;
@values .= map({ $^val.?eigenstates // $^val }) while
@values.grep(Junction);
return uniq(@values).grep($j) does ::Transjunction;
}

sub eigenvalues (Junction $j) is export { $j.eigenvalues }
}


# Transjunctions are just lists that autofilter when matched...
role Transjunction {
method ACCEPTS (Mu $filter) { self.grep($filter) }
}


# Convenient functions to build transjunctions...
multi sub every (*...@list is copy) returns Transjunction is export {
return @list does Transjunction;
}

multi sub every (Junction $j) is export {
return eigenvalues($j) does Transjunction;
}


# Comparing against a transjunction filters it with the comparison
# Rakudo star seems to require we provide two versions, though
# I had expected the Mu version ought to handle both Junctions and Anys...
multi sub infix:«»  (Transjunction $list, Mu $n) is export
{ $list.grep( *   $n ) does Transjunction }
multi sub infix:«»  (Transjunction $list,$n) is export
{ $list.grep( *   $n ) does Transjunction }
multi sub infix:«»  (Transjunction $list, Mu $n) is export
{ $list.grep( *   $n ) does Transjunction }
multi sub infix:«»  (Transjunction $list,$n) is export
{ $list.grep( *   $n ) does Transjunction }
multi sub infix:«=» (Transjunction $list, Mu $n) is export
{ $list.grep( * = $n ) does