Re: Tweaking junctions
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
-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
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
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
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
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
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
Tweaking junctions
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. Specificially, in S32-setting-library_Containers.pod, we currently have: =item !eigenstates method !eigenstates (Junction $j: -- Parcel) Returns an unordered list of the values that constitute the junction (formerly called C.values). It flattens nested junctions of the same type, so C(1|(2|3)).eigenstates returns an arbitrary permutation of the list C1, 2, 3. The problem is the *name* of that method. By definition, the eigenstates of a junction are those non-superimposed values to which the junction's superimposed values could actually collapse. Or, to put it another way, those non-superimposed values that a junction would actually match. That is, a C$value is an eigenstate of a C$junction if-and-only-if: $value !~~ Junction$value ~~ $junction 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. That's because junctions often contain internal values to which *externally* they cannot actually collapse...and hence cannot actually match. Some examples, to illustrate the distinction: Internal states Actual eigenstates Junction(what !eigenstates returns) (what junction could match) = === === any(1,2,3) 1, 2, 3 1, 2, 3 all(1,2,3) 1, 2, 3 none one(1,2,3) 1, 2, 3 1, 2, 3 none(1,2,3) 1, 2, 3 infinitely many any(12, 23) all(1,2), all(2,3)none all(1|2, 2|3) any(1,2), any(2,3)2 one(1|2, 23) any(1,2), all(2,3)1, 2 one(1|2, 2|3) any(1,2), any(2,3)1, 3 So the two problems are: 1. $j!eigenstates doesn't return $j's eigenstates (i.e. the method is misnamed) 2. $j!eigenstates doesn't return $j's eigenstates (i.e. there's no way to get a junction's actual eigenstates, which is a very useful thing to be able to do--see below) Problem 1 could be solved by renaming the method C!eigenstates to something like: C!internal-states. And, of course, renaming the corresponding attribute in the Junction class from C$!eigenstates to something like C$!internal-states. Problem 2 could be solved by defining a new (and public!) C.eigenstates method in the Junction class. This method would be implemented as something like: method eigenstates(Junction $j: -- List) is cached { # No feasible way of representing the eigenstates of an injunction... fail if $j!type ~~ JUNCTION_TYPE_NONE; # Candidates for eigenstates are all the junction's internal values... my @possible-eigenstates = $j!internal-states; # Or, rather, candidates are all its *non-superimposed* internal values # so we need to iteratively flatten any superimposed values... @possible-eigenstates .= map({$^value ~~ Junction ?? $^value!internal-states !! $^value}) while @possible-eigenstates.grep(Junction); # Actual eigenvalues are those unique candidates # that successfully match the original junction... return uniq(@possible-eigenstates).grep($j); } There is no need for this new C.eigenstates method to be private, because it doesn't expose the internal data of its junction object, but rather calculates a useful external property of that object. Some examples of why that the actual eigenstates of a junction are useful (note that these all assume the above (re)definition of C.eigenstates): # Find the list of common elements in two lists... sub intersection (@list1, @list2) { (any(@list1) any(@list2).eigenstates; } # Find the factors of a number... sub factors (Num $n) { ( $n/any(1..$n) ).eigenstates.grep({ $^q.Int == $q }); } # 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); } If nothing else, we really do need to rename the current C!eigenstates method. Damian PS: I also note that the most recent release of Rakudo* defines the C.eigenstates method as public, which is inconsistent with the current specification. That probably needs to be fixed as well.
Assigning duplicate values to several hash keys using junctions?
Hello all, I was curious if this is possible in Perl 6: %hash{ 'foo' 'bar' } = 'some value'; # %hash{'foo'} eq 'some value' and %hash{'bar'} eq 'some value' or perhaps %hash{ 'foo' | 'bar' } = 'some value'; In other words, is it possible to assign the same value to multiple hash keys simultaneously using junctions (or some other new mechanism)? In Perl 5, I would do $hash{'foo'} = $hash{'bar'} = 'some value'; which gets tedious with more than one hash key. An alternative is always @hash{qw(foo bar)} = ('some value') x 2; which is probably %hashfoo bar = ('some value') x 2; in Perl 6, but you always need to take care to write the correct integer in the list replication. The best way is, of course, (in Perl 5) { my @keys = qw(foo bar); @ha...@keys} = ('some value') x @keys; } but then you need the @keys array, which needs to be defined if you are dealing with literal values. Reading the synopses, one possibility seems to be %hashfoo bar = 'some value'; using hyper operators, but is that really the best way? Regards, Ville Koskinen
Re: Assigning duplicate values to several hash keys using junctions?
2009/6/8 Ville Koskinen vrk...@iki.fi: Hello all, I was curious if this is possible in Perl 6: %hash{ 'foo' 'bar' } = 'some value'; # %hash{'foo'} eq 'some value' and %hash{'bar'} eq 'some value' By autothreading, this would be equivalent to: (%hash{'foo'} %hash{'bar'}) = 'some value'; which in turn is the same as: (%hash{'foo'} = 'some value') (%hash{'bar'} = 'some value'); So yes, this is possible. -- Jonathan Dataweaver Lang
Re: Assigning duplicate values to several hash keys using junctions?
On Mon, Jun 08, 2009 at 12:02:43PM +0100, Ville Koskinen wrote: : An alternative is always : : @hash{qw(foo bar)} = ('some value') x 2; : : which is probably : : %hashfoo bar = ('some value') x 2; : : in Perl 6, but you always need to take care to write the correct integer : in the list replication. Two problems. First, list replicaiton is xx rather than x, and second, you *don't* have to write the integer, because you can use the Whatever star: %hashfoo bar = 'some value' xx *; That makes an arbitrarily long list of strings. : The best way is, of course, (in Perl 5) : : { :my @keys = qw(foo bar); :@ha...@keys} = ('some value') x @keys; : } : : but then you need the @keys array, which needs to be defined if you are : dealing with literal values. Perl 6's new * term is useful in many such places where you just want to say, I dunno, you figure it out. : Reading the synopses, one possibility seems to be : : %hashfoo bar = 'some value'; : : using hyper operators, but is that really the best way? If you'll define best way, I'll tell you if it is. :) The relative efficiency is going to be difficult to predict because any of these could be poorly implemented and do too much busywork. Apart from that, it's gonna come down primarily to what you think is readable. By the way, infix hypers want to go on both sides, like this: %hashfoo bar »=» 'some value'; Larry
Re: junctions and conditionals
Dave Whipp wrote: I'm thinking that the solution to this issue may be a little more radical than to-date: don't permit junctions to be stored in $ variables! Instead, require junctions to use a twiggle, to alert the reader that the surprises may be lurking. my $x = 1|2; #error my $|x = 1|2; # ok Then you just need to invent some syntax to say that collapse is (or perhaps isn't) desired: if [[ $|x 1 ]] { say $|x collapsed } The most important thing that this does is that it leaves open the option to allow $ variables to hold junctions in some future version of Perl, without that future version being constrained by legacy semantics. I'd second the twigil idea. Reason: I'd -really- like perl6 to be compilable into an efficient machine code without a JIT magic that we can currently only handwave about. For that, I'd propose a rule of a thumb: ints are ints. Of course, floats and other unboxed types should also be just plain unboxed types, but I'd like the rule of a thumb to be short and to the point. So, int $x = 1|2; should be an error. Also, int $x = 1 but not really a number; should also be an error or at least a warning that mixin stripping and unboxing took place. If you want polymorphic here, use Ints. That'd also mean that my @x of int; can be implemented as a homogenous int vector, meaning -really- efficient and manipulable through the kind of code that modern CPUs are really good at (since as soon as you know you won't be lazy, you only need to be polymorphic about asking for the beginning of the in-memory buffer that can be manipulated directly. Even if that buffer doesn't contain all the elements, you can refill it as needed, and that could still be fast as long as the other side of the partially-lazy barrier also speaks int). Also, as far as I'm aware, there is no tracing VM that can create a homogenous arrays for you if you can't already do them. From the above, the need for twigils in junctions should be apparent. Miro
Re: [Fwd: Re: junctions and conditionals]
On Wed, 1 Apr 2009, Richard Hainsworth wrote: A closer examination of Martin's message indicates that he tends to think that hitting a junction ought to thread the entire program throughout the rest of the lifespan of said junction Yes -- and well put, thank-you. The trick is that since conditionals generally force full or partial resolution on junctions, that lifetime won't tend to be very long. Re: Tsa's comment about junctions being value types. In principle I agree, except that the value semantics are only within the eigenthreads; outside that, they are collections of indeterminate state. Indeterminate states aren't sufficiently value-like to justify constant folding. -Martin
Re: simultaneous conditions in junctions
On Wed, 1 Apr 2009, John Macdonald wrote: If I understand correctly, (which is by no means assured) a function call with a junction as an argument generally acts as if it were autothreaded. So: $x = any(1,2,3); $y = f($x); should work like: $y = any( f(1), f(2), f(3) ); Right? In general yes. However if f involves some kind of truth inversion then logically f(any(@x)) == all(map.assuming(f).(@x)) and f(all(@x)) == any(map.assuming(f).(@x)) I have in mind something like these in the standard preamble: prefix:«!»(Bool) does(junctive_inversion) prefix:«not»(Bool) does(junctive_inversion) infix:«ne»(String,String) does(junctive_inversion) infix:«!=»(Num,Num)does(junctive_inversion) infix:«!==»(Object,Object) does(junctive_inversion) (Excuse the rather lose syntax, but I hope you get the idea.) -Martin
Re: junctions and conditionals
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
Re: simultaneous conditions in junctions
Larry Wall wrote: On Wed, Apr 01, 2009 at 08:40:12AM -0700, Dave Whipp wrote: That said, the semantics of a chained relop really should work correctly for this. If you only reference a junction once in an expression, then it should behave as such: {abc} !=== {ab bc}. Yes, that is the intent. I consider a chained 1 $x 2 to be a single function from the standpoint of autothreading, something like chained(1, infix:«», $x, infix:«», 2); and the semantics would fall out of that naturally, more or less. Something similar could also work for the blocks of conditionals if we were to treat the conditional as a function that autothreads consistently over both its condition and its blocks; this implies the junction autothreader must be given enough access to the scope of the block in question to temporarily override the value of $x within the block to its autothreaded value somehow. The tricky bit is that autothreading is setting up extra scopes around variant captures without explicit blocks. That alone is reason enough to keep the mechanism all internal. Do I understand correctly from this that my $x = 1|5; say ?(2 $x $4) ; # False my $x = 1|3|5; say ?(2 $x $4); # True If so, then the current implementation of rakudo is generating an error, viz., $ perl6 my $x=1|5; say ?( 2 $x 4) 1 May be something extra needs to be added to the specs? If we do give access to universe of values the junction is interested in, it should probably just be via a coercion to Set. This would give the necessary extra syntax to ensure that the programmer knows what s/he is doing. It means that junctions could be threshed and sieved when desired. There would have to be some caveats about using that as the universe of values, however, since none() junctions define a set outside of the eigenstates. Interesting. Do I understand this correctly: If the junction is finite, then none() defines an infinite set, and vice versa. But then if perl6 is lazy, an infinite set would also be possible With access being lazily evaluated. Just as 0 .. inf is lazily evaluated? For that reason I'd still prefer people to track their universe of values outside the junctions rather than rely on junctions for that. And of course, a Set in list context is its members, so any(%set) isn't a problem going the other direction. Larry
simultaneous conditions in junctions
Thinking about Jon Lang's -1|+1 example in another way, I wondered about simultaneous conditions. Consider $x = any (1,2,5,6) How do we compose a conditional that asks if any of this set of eigenstates are simultaneously both 2 and 5? Clearly the desired answer for $x is False, but my $x = any(1,2,5,6); say ?( 2 $x 5); # true Is there some combination of any/all that will achieve this? Here it would seem that we would want to have some sieving, so that eigenstates that are true for one test can be given to another test.
Re: simultaneous conditions in junctions
Richard (): Consider $x = any (1,2,5,6) How do we compose a conditional that asks if any of this set of eigenstates are simultaneously both 2 and 5? Clearly the desired answer for $x is False, but my $x = any(1,2,5,6); say ?( 2 $x 5); # true Is there some combination of any/all that will achieve this? my @x = 1, 2, 5, 6; say ?(first { 2 $_ 5 }, @x); # false Problem solved. It doesn't involve the cool junctions technology, but it's not much longer, and perhaps slightly more understandable. // Carl
[Fwd: Re: junctions and conditionals]
This email was mistakenly not sent to the p6l list. Jon writes: On Wed, Apr 1, 2009 at 12:54 AM, Richard Hainsworth rich...@rusrating.ru wrote: Jon Lang wrote: In Junction Algebra, Martin Kealey wrote: On Mon, 30 Mar 2009, Mark J. Reed wrote: ( $a = any(-1,+1) = $b ) == ( $a = any(-1,+1) any(-1,+1) = $b )(*A) Clearly, the RHS is true for $a == $b == 0, but I'm not sure the LHS shouldn't also be. Isn't it just syntactic sugar for the RHS? I suspect not. Rather I think that $a = any(-1,+1) = $b corresponds to $tmp = any(-1,+1); $a = $tmp = $b and thence to $tmp = any(-1,+1); $a = $tmp $tmp = $b (*B*) Quite how the lines I have labelled (A) and (*B*) are different, I do not understand. Unless wrapping a junction in a variable produces a different result. That was my initial reaction as well. A closer examination of Martin's message indicates that he tends to think that hitting a junction ought to thread the entire program throughout the rest of the lifespan of said junction, so that (e.g.) the thread that runs the comparison $a = -1 in (*B*) is the same thread that runs the comparison -1 = $b. OTOH, since (*A*) spells out two separate junctions, it would thread each one separately; resulting in four threads being used to resolve the expression. In theory, at least; in practice, he's looking for ways to simulate such threading without actually having to mess with all of the overhead that a literal implementation thereof would entail. In both cases, the problem arises when you apply a predicate to a junction, and then use the junction within code that only gets executed according to the truth of the predicate. Using a junction implies the extraction of the eigenstates. That is being frowned upon - I understand I've been doing my utmost to avoid making said implication. The possible solution to both of these: junctions collapse when they hit conditional statements - but only within the conditioned scope. So: within the code block for the if $x 0 statement above, $x only equals +1, since -1 didn't pass the test. This is the sieving functionality. Since perl6 is being written explicitly to avoid sieving out eigenstates, this will not happen. What I'm hearing is that a decision has already been made on this matter, so we're stuck with it no matter how counterintuitive the results of that decision are. Thus, say $x is the same as say 1. In the case of the range test, the code on the RHS of the only executes if the code on the LHS evaluated to true; therefore, when evaluating the RHS, $tmp doesn't include any of the possibilities that would have failed on the LHS. That means that: 0 = -1 | +1 = 0 which is true, because using standard chaining semantics we have 0 = -1|1 and -1|1 = 0 Since the first condition is true (+1 = 0) and the second condition is true (-1 =0), the compound is true. Why you might want such a condition, I dont know. But that is the way junctions are designed to work. Right now, yes. I'm arguing that the way that they're designed to work doesn't DWIM. Try a slightly different example: 0 = $x = 1 # 0 is less than $x is less than 1. $x ~~ 0..1 # $x is in the range of 0 to 1. I submit that most people would expect these two statements to be conceptually equivalent to each other: they may go about tackling the issue from different angles, but they should always end up reaching the same conclusion. But as things stand now, if $x = -2 | 2, these result in two very different conclusions: the first evaluates as true, the second as false. This most certainly doesn't do what I mean until I have been indoctrinated into the intricacies of Perl and learned to think like it does - which runs directly counter to the principle of DWIM. Perhaps instead of 0 = any(-1,1) = 0, the programmer might want 0 = all(-1,1) = 0, which is false. You're assuming that the programmer gets to choose which junction he's sticking in the middle of the comparison chain. ...becomes: 0 = -1 | +1 +1 = 0 ...which, obviously, is false. The question really is what is the desired meaning of this conditional. Yes. And my answer is that the desired meaning of 0 = -1 | +1 = 0 is closer to (0 = -1 = 0) or (0 = +1 = 0) than it is to (0 = -1 or 0 = +1) and (-1 = 0 or +1 = 0). The trick is to figure out how to get this result without needing a nightmarish amount of overhead to do it. -- Jonathan Dataweaver Lang
Re: simultaneous conditions in junctions
On Wed, Apr 1, 2009 at 12:58 AM, Richard Hainsworth rich...@rusrating.ru wrote: Thinking about Jon Lang's -1|+1 example in another way, I wondered about simultaneous conditions. Consider $x = any (1,2,5,6) How do we compose a conditional that asks if any of this set of eigenstates are simultaneously both 2 and 5? Clearly the desired answer for $x is False, but my $x = any(1,2,5,6); say ?( 2 $x 5); # true Is there some combination of any/all that will achieve this? As Carl indicated, there are other ways to do this. For instance, s/ 2 $x 5 / $x ~~ 2 ^..^ 5 /. But as I indicated in a recent email, part of my concern is that those two expressions _ought to be_ equivalent: changing the junction, or making do without one as Carl proposes, doesn't fix this lack of equivalence. As for Carl's proposed alternative: no, it isn't _much_ longer (but it _is_ longer), and _perhaps_ it's _slightly_ more understandable - or perhaps not. Other than making the implementors' lives harder, what's wrong with trying to find a way to get Jonathan's example to work the way people expect it to? I don't understand this aversion to everything remotely hinting of eigenstates/eigenthreads/threshing/whatever. -- Jonathan Dataweaver Lang
Re: [Fwd: Re: junctions and conditionals]
On Wednesday, April 01 2009 07:38 am, Richard Hainsworth wrote: Right now, yes. I'm arguing that the way that they're designed to work doesn't DWIM. Try a slightly different example: 0 = $x = 1 # 0 is less than $x is less than 1. $x ~~ 0..1 # $x is in the range of 0 to 1. I submit that most people would expect these two statements to be conceptually equivalent to each other: they may go about tackling the issue from different angles, but they should always end up reaching the same conclusion. But as things stand now, if $x = -2 | 2, these result in two very different conclusions: the first evaluates as true, the second as false. This most certainly doesn't do what I mean until I have been indoctrinated into the intricacies of Perl and learned to think like it does - which runs directly counter to the principle of DWIM. When you say DWIM, I take it you mean that there is an assumption that $x is a point in a field (http://en.wikipedia.org/wiki/Field_theory_(mathematics)). As you have illustrated, junctions do no form a field. You would run into the similar problems if $x was a point in a ring (http://en.wikipedia.org/wiki/Ring_(mathematics)). Consider the ring of integers modulo 8: my Ring8 $x = 5 + 3;# evaulates to 0 say OMG, its 0! unless $x;# prints the message which does not DWIM if I am expecting $x to be part of a field. Maybe the problem is that junctions are too easy to create, which is causing people to confuse the mathematical structure of the space created by using a junction with that of the structure of the space of the underlying (non-junctioned) object. Regards, Henry
Re: simultaneous conditions in junctions
The idea is that junctions should usually be invisible to the code, and autothreading handles them behind the scenes. Once you start using the eigenstates as a collection, you're breaking the model and not gaining anything over just using a regular collection type. But the behind the scenes model fails when a junction passes through a condition into guarded code that assumes the condition is true, unless the eigenstates inside the guard are restricted to those for which the condition is true. Consider: my $x = 2|0; my $y = $x ?? 1/$x !! 0; The expected result is presumably $y == 0|.5, but if the $x in the denominator isn't restricted to the eigenstates that pass the conditional, you get a divide by zero in one of the autothreads. The code needs to behave as if each eigenstate is treated independently by a separate thread, and only combined back into a junction at the end of each autothreaded block, even if the implementation doesn't actually do it that way. We can't just test a junction using its junctive semantics and fall through with the junction intact. To go back to the Blackjack example: for junctions to apply, code written with the assumption that each hand's sum is a simple number should work when they're actually junctions. But that's not the case because the end goal is to pick a single winner, not a junction of possible winners depending on how you assign values to the Aces. There are specific rules for the selection of Ace values that don't necessarily follow junctive semantics, and just letting things thread through will not yield the right answer in all cases. (Yes, for those keeping score at home, I changed my mind about the applicability of junctions to that problem...) On 4/1/09, Jon Lang datawea...@gmail.com wrote: On Wed, Apr 1, 2009 at 12:58 AM, Richard Hainsworth rich...@rusrating.ru wrote: Thinking about Jon Lang's -1|+1 example in another way, I wondered about simultaneous conditions. Consider $x = any (1,2,5,6) How do we compose a conditional that asks if any of this set of eigenstates are simultaneously both 2 and 5? Clearly the desired answer for $x is False, but my $x = any(1,2,5,6); say ?( 2 $x 5); # true Is there some combination of any/all that will achieve this? As Carl indicated, there are other ways to do this. For instance, s/ 2 $x 5 / $x ~~ 2 ^..^ 5 /. But as I indicated in a recent email, part of my concern is that those two expressions _ought to be_ equivalent: changing the junction, or making do without one as Carl proposes, doesn't fix this lack of equivalence. As for Carl's proposed alternative: no, it isn't _much_ longer (but it _is_ longer), and _perhaps_ it's _slightly_ more understandable - or perhaps not. Other than making the implementors' lives harder, what's wrong with trying to find a way to get Jonathan's example to work the way people expect it to? I don't understand this aversion to everything remotely hinting of eigenstates/eigenthreads/threshing/whatever. -- Jonathan Dataweaver Lang -- Sent from my mobile device Mark J. Reed markjr...@gmail.com
Re: simultaneous conditions in junctions
On Wed, Apr 01, 2009 at 09:44:43AM -0400, Mark J. Reed wrote: The idea is that junctions should usually be invisible to the code, and autothreading handles them behind the scenes. [ ... ] If I understand correctly, (which is by no means assured) a function call with a junction as an argument generally acts as if it were autothreaded. So: $x = any(1,2,3); $y = f($x); should work like: $y = any( f(1), f(2), f(3) ); Right? sub f($x) { return $x 1.5 $x ?? $x :: undef; } $y = f($x); $z = $x 1.5 $x ?? $x :: undef; Unless autothreading is also implied by conditionals, $y and $z would have significantly different results; $y === any(undef,undef,undef) while $z === any(1,2,3). But, if autothreading *is* implied by conditionals, where do the threads get joined? I have a feeling that the autothreading has to happen essentially at the point of the creation of the junction to avoid getting a result from a junction that none of the joined quantities is capable of justifying (such as the one described ealier of (-4|4) matching the criteria to be in the range 0..1). I suspect that juctions will be perl6's action-at-a-distance hazard. (With quantum entanglement, you get action-at-a-distance effects in the real world. When we import them into a computer language, the resulting action-at-a-distance should come as no surprise - except for its inherent surprise/hazard nature.) Now, if it is acceptable for -4|4 to return true for 0 = $x = 1 when tested directly in an expression, but to return false if it is tested in a subroutine, then perl6 junctions are not really modelling quantum superpositions and I, at least, will need to find a different metaphor for what they actually do do (and for what they can be used for and when).
Re: simultaneous conditions in junctions
Richard Hainsworth wrote: Thinking about Jon Lang's -1|+1 example in another way, I wondered about simultaneous conditions. Consider $x = any (1,2,5,6) How do we compose a conditional that asks if any of this set of eigenstates are simultaneously both 2 and 5? Clearly the desired answer for $x is False, but my $x = any(1,2,5,6); say ?( 2 $x 5); # true Is there some combination of any/all that will achieve this? Here it would seem that we would want to have some sieving, so that eigenstates that are true for one test can be given to another test. One answer is to use grep: $x = any (1,2,5,6); say ?( (2^..^5).grep: { $_ == $x } ); # False This isn't, of course, quite what you asked for, because the semantics of relops are continuous. So you'd want something like: $x = any (1,2, 2.5, 5,6); say ?( (2^..^5 :real).grep: { $_ == $x } ); # False (or whatever the syntax for a continuous range is). That might take a while to complete, hence my desire for an analytic grep That said, the semantics of a chained relop really should work correctly for this. If you only reference a junction once in an expression, then it should behave as such: {abc} !=== {ab bc}.
Re: junctions and conditionals
HaloO, 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 This is an example why the controlled block should not be auto-threaded. That is the assembly point of the resulting junction any(0,0,0,0,0,1,1,1,1,1) is before the block. Thus I'm opting for any(-4..6). Regards, TSa. -- The unavoidable price of reliability is simplicity -- C.A.R. Hoare Simplicity does not precede complexity, but follows it. -- A.J. Perlis 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan
Re: [Fwd: Re: junctions and conditionals]
HaloO, Richard Hainsworth wrote: ( $a = any(-1,+1) any(-1,+1) = $b )(*A) [..] $tmp = any(-1,+1); $a = $tmp $tmp = $b (*B*) Quite how the lines I have labelled (A) and (*B*) are different, I do not understand. Unless wrapping a junction in a variable produces a different result. That was my initial reaction as well. A closer examination of Martin's message indicates that he tends to think that hitting a junction ought to thread the entire program throughout the rest of the lifespan of said junction, so that (e.g.) the thread that runs the comparison $a = -1 in (*B*) is the same thread that runs the comparison -1 = $b. OTOH, since (*A*) spells out two separate junctions, it would thread each one separately; resulting in four threads being used to resolve the expression. In theory, at least; in practice, he's looking for ways to simulate such threading without actually having to mess with all of the overhead that a literal implementation thereof would entail. I like to throw in that junctions are value types. That is the two literal junctions in (*A*) are one and the same object and hence the global auto-threading should be the same as with an explicit variable. I like the idea of global auto-threading because it matches the behavior of the unitary state changes of quantum systems. That is it is the individual states that interact in a non-entangled fashion as part of a larger ensemble of execution paths ala Feynman. Just as in quantum mechanics there are collapse points of junctions in boolean context e.g. in an if statement. But if we define that is not collapsing than it becomes part of a scope that a junction auto-threads through. Note that the collapse points are statically known from the structure of the source code! Literal junctions within this stretch of code need to be assembled as implicit parameters of the code block that implements the conditional of an if block. With the parameters upfront it is unimportant if the runtime systems starts multiple threads or iterates the junction sequentially. But a lightweight thread implementation boosts performance, of course. An important thing that has to go into the spec is how side-effective code is handled in conditionals. E.g. if $x.foo $x.bar $x.baz {...} first of all is specced to evaluate $x.bar only ones. But is it also specced that the three calls are evaluated left to right such that .foo can influence .bar? Also the $x.baz can be short circuited. The point I want to make is that in quantum computation a NOT gate *does* flip the individual value of the entangled states of a qubit. That is !any(0,1) becomes any(1,0) in such a way that it knows which 0 has become 1 and vice versa for as long as the scope of the junction runs. As of now this negation in Perl 6 is a no-op! And we should stop to compare the current junctions to quantum superposition! Other equivalences should hold as well. E.g. if one expands $x ^ $y to (!$x $y) || ($x !$y) it should result in the same program behavior irrespective of $x or $y being junctions. In both cases, the problem arises when you apply a predicate to a junction, and then use the junction within code that only gets executed according to the truth of the predicate. This implies that junctions also thread through the controlled block of an if. I hope that my assertion that structural analysis of the code suffices to define the points where the auto-threads are re-assembled into a junction still holds in this case. What I'm hearing is that a decision has already been made on this matter, so we're stuck with it no matter how counterintuitive the results of that decision are. You mean the decision that junction is now a native type with a private .eigenstates method? I think that is reasonable. The nativeness of the type is reflected in the fact that the junctive behavior becomes a structural property of the code. That is the junction as such has no magic. This magic is in the compiler! The junction as a native type is a simple list of values. The above to me implies BTW some finer control for signatures to specify what kind of junction they allow. E.g. :(Int $) auto-threads from the outside, :(Object $) passes a junction without auto-threading. But is :(junction of Int $) the right way to say that you want to deal with any(1,2,3) but not any('a','b','c')? That means that: 0 = -1 | +1 = 0 which is true, because using standard chaining semantics we have 0 = -1|1 and -1|1 = 0 No, there should be an outer scope that is in charge of auto-threading the junction through which was created by the compiler from the -1|+1 even though it sits in the middle of the conditional. I would call that junction propagation. Since the first condition is true (+1 = 0) and the second condition is true (-1 =0), the compound is true. Why you might want such a condition, I dont know. But that is the way junctions
Re: junctions and conditionals
Jon Lang wrote: [proposal that conditional statements should collapse junctions] $x = +1 | -1; if $x 0 { say $x is positive. } else { say $x is negative. } I suspect that both codeblocks would be executed; but within the first block, $x == +1, and within the second codeblock, $x == -1. The problem I see with this (other than implementation issues) is that it would lead to unintuitive behavior in some cases: my $x = one(10,20); if $x 15 { # here, $x collapsed to 20 if $x 5 { say $x 5 } else { say not $x 5 } } if $x 5 { say $x 5 } else { say not $x 5 } Some people might be surprised if the two tests of $x 5 result in two different results. I don't think that there is any single semantics that won't cause surprises (unintuitive behavior) in some cases. So I'd vote for going with simple semantics that are easy to explain -- that is, don't attempt implicit junctional collapse. Provide operators to collapse when needed, but don't attempt to be too clever.
Re: simultaneous conditions in junctions
HaloO, John Macdonald wrote: Unless autothreading is also implied by conditionals, $y and $z would have significantly different results; $y === any(undef,undef,undef) while $z === any(1,2,3). This is why I'm opting for statical analysis of auto-threaded conditionals. But, if autothreading *is* implied by conditionals, where do the threads get joined? Right after the conditional, of course. From there it could be necessary to branch into both blocks however if you have a result of any(0,1) and an else block. ?? !! essentially behaves like an if else. Question is how this applies to user defined control structures. I have a feeling that the autothreading has to happen essentially at the point of the creation of the junction to avoid getting a result from a junction that none of the joined quantities is capable of justifying (such as the one described ealier of (-4|4) matching the criteria to be in the range 0..1). I suspect that juctions will be perl6's action-at-a-distance hazard. (With quantum entanglement, you get action-at-a-distance effects in the real world. Quantum entanglement is no action at a distance because you can't transfer anything with the collapse. The local appearance is that of a normal quantum measurement. Only if you communicate information by traditional means you can compare *measurements*. The common misconception of Quantum Mechanics is that it is about small things whereas a two photons system can span galaxies. When we import them into a computer language, the resulting action-at-a-distance should come as no surprise - except for its inherent surprise/hazard nature.) Now, if it is acceptable for -4|4 to return true for 0 = $x = 1 when tested directly in an expression, but to return false if it is tested in a subroutine, then perl6 junctions are not really modelling quantum superpositions I agree. We should make sure that junctions model quantum computations. Regards, TSa. -- The unavoidable price of reliability is simplicity -- C.A.R. Hoare Simplicity does not precede complexity, but follows it. -- A.J. Perlis 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan
Re: junctions and conditionals
On Wed, Apr 1, 2009 at 11:49 AM, Dave Whipp d...@dave.whipp.name wrote: The problem I see with this (other than implementation issues) is that it would lead to unintuitive behavior in some cases: my $x = one(10,20); if $x 15 { # here, $x collapsed to 20 if $x 5 { say $x 5 } else { say not $x 5 } } if $x 5 { say $x 5 } else { say not $x 5 } Some people might be surprised if the two tests of $x 5 result in two different results. That's surprising, yes, but I'd say the surprise comes from the fact that it's a one() junction, which has extra weirdness on top of the general junctional weirdnesses. So yes, if we collapse the junction, $x is both 5 and not 5 according to the output. If we *don't* collapse, $x will consistently fail the $x 5 test - but then you have a value that is somehow both greater than 15 and not greater than 5, which I would still call surprising. I don't think that there is any single semantics that won't cause surprises (unintuitive behavior) in some cases. Probably true. So I'd vote for going with simple semantics that are easy to explain -- that is, don't attempt implicit junctional collapse. Provide operators to collapse when needed, but don't attempt to be too clever. While it's easier to find clever programmers than to write clever software, the gains from the latter are significant, as Larry's work pre- and post-Perl has repeatedly demonstrated. When a language implementation provides a feature like junctions that is arguably too clever by half to start with, I'd rather there be a commensurate amount of cleverness in the support of that feature. Basically, I want the specified behavior to make sense as much as possible, and for it to be easy to explain the places where it doesn't seem to make sense. Even if it means we don't get that behavior in 6.0.0. -- Mark J. Reed markjr...@gmail.com
Re: simultaneous conditions in junctions
On Wed, Apr 01, 2009 at 08:40:12AM -0700, Dave Whipp wrote: That said, the semantics of a chained relop really should work correctly for this. If you only reference a junction once in an expression, then it should behave as such: {abc} !=== {ab bc}. Yes, that is the intent. I consider a chained 1 $x 2 to be a single function from the standpoint of autothreading, something like chained(1, infix:«», $x, infix:«», 2); and the semantics would fall out of that naturally, more or less. Something similar could also work for the blocks of conditionals if we were to treat the conditional as a function that autothreads consistently over both its condition and its blocks; this implies the junction autothreader must be given enough access to the scope of the block in question to temporarily override the value of $x within the block to its autothreaded value somehow. The tricky bit is that autothreading is setting up extra scopes around variant captures without explicit blocks. That alone is reason enough to keep the mechanism all internal. If we do give access to universe of values the junction is interested in, it should probably just be via a coercion to Set. There would have to be some caveats about using that as the universe of values, however, since none() junctions define a set outside of the eigenstates. For that reason I'd still prefer people to track their universe of values outside the junctions rather than rely on junctions for that. And of course, a Set in list context is its members, so any(%set) isn't a problem going the other direction. Larry
Re: junctions and conditionals
Mark J. Reed wrote: [I] wrote: So I'd vote for going with simple semantics that are easy to explain -- that is, don't attempt implicit junctional collapse. Provide operators to collapse when needed, but don't attempt to be too clever. While it's easier to find clever programmers than to write clever software, the gains from the latter are significant, as Larry's work pre- and post-Perl has repeatedly demonstrated. When a language implementation provides a feature like junctions that is arguably too clever by half to start with, I'd rather there be a commensurate amount of cleverness in the support of that feature. Basically, I want the specified behavior to make sense as much as possible, and for it to be easy to explain the places where it doesn't seem to make sense. Even if it means we don't get that behavior in 6.0.0. I'm thinking that the solution to this issue may be a little more radical than to-date: don't permit junctions to be stored in $ variables! Instead, require junctions to use a twiggle, to alert the reader that the surprises may be lurking. my $x = 1|2; #error my $|x = 1|2; # ok Then you just need to invent some syntax to say that collapse is (or perhaps isn't) desired: if [[ $|x 1 ]] { say $|x collapsed } The most important thing that this does is that it leaves open the option to allow $ variables to hold junctions in some future version of Perl, without that future version being constrained by legacy semantics.
Re: junctions and conditionals
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) 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.)
junctions and conditionals
In Junction Algebra, Martin Kealey wrote: On Mon, 30 Mar 2009, Mark J. Reed wrote: ( $a = any(-1,+1) = $b ) == ( $a = any(-1,+1) any(-1,+1) = $b ) Clearly, the RHS is true for $a == $b == 0, but I'm not sure the LHS shouldn't also be. Isn't it just syntactic sugar for the RHS? I suspect not. Rather I think that $a = any(-1,+1) = $b corresponds to $tmp = any(-1,+1); $a = $tmp = $b and thence to $tmp = any(-1,+1); $a = $tmp $tmp = $b The more I think about this, the more I come to the conclusion that a junction should appear to have a uniform (single) value in each eigenthread. Ugh. Let me float another problem, and a possible solution to both, that doesn't require persistent threading environments: $x = -1 | +1; if $x 0 { say $x } As I understand junctions right now, the result of this code is identical to: say -1 | +1; In both cases, the problem arises when you apply a predicate to a junction, and then use the junction within code that only gets executed according to the truth of the predicate. The possible solution to both of these: junctions collapse when they hit conditional statements - but only within the conditioned scope. So: within the code block for the if $x 0 statement above, $x only equals +1, since -1 didn't pass the test. Thus, say $x is the same as say 1. In the case of the range test, the code on the RHS of the only executes if the code on the LHS evaluated to true; therefore, when evaluating the RHS, $tmp doesn't include any of the possibilities that would have failed on the LHS. That means that: 0 = -1 | +1 = 0 ...becomes: 0 = -1 | +1 +1 = 0 ...which, obviously, is false. Extending this further: $x = +1 | -1; if $x 0 { say $x is positive. } else { say $x is negative. } I suspect that both codeblocks would be executed; but within the first block, $x == +1, and within the second codeblock, $x == -1. $x = +1 | -1; say $x 0 ?? $x + 2 :: $x * 2; In this case, $x is +1 when evaluating $x + 2, and it is -1 when evaluating $x * 2. After this expression is fully evaluated, they get recombined into a single junction: +3 | -2. This last one might be easier to manage simply by having $x autothread through the ?? :: operator, since you need to be able to reassemble a junction on the other end. -- Jonathan Dataweaver Lang
Re: junctions and conditionals
I've been having some second thoughts concerning this. Here's where I stand on it now: In Perl 6, you have the following decision points, where code may or may not be executed depending on a condition: if/unless/while/until/loop/when statements; if/unless/while/until statement modifiers; short-circuit operators; the trinary conditional operator. When you apply a junction to a decision point, only one of the possible paths will be taken; and the any/all/one/none nature of the junction will determine which one. (Without this, there would be no reason to have a distinction between any/all/one/none.) However, I stand by my proposal that after passing one of these decision points, and until you get back to code that would have been reached regardless of the decision point, every junction that was involved in the decision point should be limited such that it acts as if only those possibilities within it that would have passed the decision point exist. With unless, while, until, and loop, the associated block is the conditional block where the junction gets filtered. With if, the main block likewise filters the junctions; but the else block also provides junction filtering, but in a way that's complementary to what the main block does. With short-circuit operators, the RHS counts as a block that provides junction filtering based on what it would take for the LHS to avoid tripping the short-circuit behavior. Similarly, ?? :: treats the expression following the ?? as a junction-filtering block and the expression following the :: as a complementary junction-filtering block, in direct analogy to if/else, above. Finally, there's the when statement: as with if, etc., the block that follows the when statement filters junctions according to the match criterion. However, when is a bit more complicated in terms of getting it to DWIM w.r.t. junctions. Because of the way that when works conceptually, I'd recommend that for the rest of the block containing the when statement, it should provide the same sort of complementary filtering that an else block does for an if statement. That is: given $x { when $a { ... } when $b { ... } when * } ...should not be thought of as being equivalent to: given $x { if $_ ~~ $a { ...; break } if $_ ~~ $b { ...; break } if $_ ~~ * {...; break } } ...but rather: given $x { if $_ ~~ $a { ... } else { if $_ ~~ $b { ... } else { if $_ ~~ * { ... } } } } -- 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 -- Jonathan Dataweaver Lang -- Jonathan Dataweaver Lang
Re: On Junctions
Em Dom, 2009-03-29 às 22:57 -0700, Mark Lentczner escreveu: What I see here is that there is a tendency to want to think about, and operate on, the eigenstates as a Set, but this seems to destroy the single value impersonation of the Junction. Further, if one ever calls .!eigenstates() on a Junction, then you have really bollox'd your code up, as then this code fails if the value you thought was a Junction happens to be, actually, just a single value! (Unless .!eigenstates() is defined on Object, and returns a Set of self...) ++ This is the most important semantic deadlock, thanks for putting it so clearly. I think what is needed is a single value threshing function, which can be applied to, well, single values. Such a function would take a value and a predicate, and if the predicate applied to the value is true, returns the value, else it returns... nothing. If such a function were applied to a Junction, then the result would be a Junction of just those those eigenstates that passed this function. The nothings would not end up contributing to the Junction. Well, that can be thought as grep. my @i = 1|11, 9, 1|11; my @j = 6,9,6; my $a = [+] @i; my $b = [+] @j; my $va = $a.grep: * = 21; my $vb = $b.grep: * = 21; if ($va $vb) { if ($va $vb) { # a wins } elsif ($vb $va) { # b wins } else { # draw } } If we have grep as a method in Any, the call to grep will autothread, returning a junction of the values, so, as $a is any(11, 21, 31), $va would be any(11,21,()), which should collapse as expected. Now, I'm not sure I know how to return nothing in Perl6, but I'll guess that undef can serve the purpose, since I can't think of a useful use of undef as part of a Junction. Well, you return nothing simply by calling return; it will produce an empty capture, which could be seen simply as (). daniel
Re: On Junctions
On Sun, Mar 29, 2009 at 10:57 PM, Mark Lentczner ma...@glyphic.com wrote: What I see here is that there is a tendency to want to think about, and operate on, the eigenstates as a Set, but this seems to destroy the single value impersonation of the Junction. In my case, this tendency comes more from a desire to be able to reverse the creation of a junction: you create a (singular) junction from a (plural) list ('1|3|5' === 'any 1, 3, 5'); so I naturally want to be able to (more or less) reverse this process and create a (plural) Set from a (singular) junction. Further, if one ever calls .!eigenstates() on a Junction, then you have really bollox'd your code up, as then this code fails if the value you thought was a Junction happens to be, actually, just a single value! (Unless .!eigenstates() is defined on Object, and returns a Set of self...) Which is why I'd _want_ eigenstates to be callable on an Object as described - and, in general, _any other_ function that operates directly on junctions should be able to accept Objects as well, treating the Object as a one-eigenstate junction. Otherwise, the moment you write a function that passes a junction as a parameter, your code will break if you ever try to pass an Object in instead. And the only other ways to avoid that would be: 1. to provide a means of testing whether or not something is a junction, or 2. to forbid anyone from ever using junction in a signature. I think what is needed is a single value threshing function, which can be applied to, well, single values. Such a function would take a value and a predicate, and if the predicate applied to the value is true, returns the value, else it returns... nothing. If such a function were applied to a Junction, then the result would be a Junction of just those those eigenstates that passed this function. The nothings would not end up contributing to the Junction. ...that could work. The only catch is that if you ever want to get a list of the cases that passed so that you can operate on them individually, you'd still need a means of extracting the eigenstates from the junction. Now, I'm not sure I know how to return nothing in Perl6, but I'll guess that undef can serve the purpose, since I can't think of a useful use of undef as part of a Junction. As Daniel indicated, returning an empty list should work. -- Jonathan Dataweaver Lang
Re: On Junctions
Jon Lang wrote: I stand corrected. That said: with the eigenstates method now private, it is now quite difficult to get a list of the eigenstates of the above expression. I thought about that a bit, and I think eigenstates are not hard to extract (which somehow makes the privateness of .eigstates a bit absurd), simply by autothreading: sub e(Object $j) { my @states; - Any $x { @states.push($x) }.($j); return @states; } Cheers, Moritz
Re: On Sets (Was: Re: On Junctions)
On Sat, Mar 28, 2009 at 10:39:01AM -0300, Daniel Ruoso wrote: That happens because $pa and $pb are a singular value, and that's how junctions work... The blackjack program is an example for sets, not junctions. Now, what are junctions good for? They're good for situation where it's collapsed nearby, which means, it is used in boolean context soon enough. Or where you know it's not going to cause the confusion as in the above code snippet. Unfortunately, it is extremely common to follow up a boolean is this true with either if so, how and/or if not, why not. A boolean test is almost always the first step toward dealing with the consequences, and that almost always requires knowing not only what the result of the boolean test were, but which factors caused it to have that result. The canonical example of quantum computing is using it to factor huge numbers to break an encryption system. There you divide the huge number by the superposition of all of the possible factors, and then take the eigenstate of the factors that divide evenly to eliminate all of the huge pile of potential factors that did not divide evenly. Without being able to take the eigenstate, the boolean answer yes, any(1..n-1) divides n is of very little value.
Re: On Sets (Was: Re: On Junctions)
On Sun, Mar 29, 2009 at 1:18 PM, John Macdonald j...@perlwolf.com wrote: On Sat, Mar 28, 2009 at 10:39:01AM -0300, Daniel Ruoso wrote: That happens because $pa and $pb are a singular value, and that's how junctions work... The blackjack program is an example for sets, not junctions. Now, what are junctions good for? They're good for situation where it's collapsed nearby, which means, it is used in boolean context soon enough. Or where you know it's not going to cause the confusion as in the above code snippet. Unfortunately, it is extremely common to follow up a boolean is this true with either if so, how and/or if not, why not. A boolean test is almost always the first step toward dealing with the consequences, and that almost always requires knowing not only what the result of the boolean test were, but which factors caused it to have that result. True point. Along these lines, I'd like to see at least one threshing function that separates a junction's eigenstates that passed a boolean test from those that didn't. I can see several possible semantics for such: 1. It returns a list of the eigenstates that passed the test. 2. It returns a junction composed of only those parts of the junction which passed the test. 3. It returns a two-item list: the wheat and the chaff. The form that the items take would conform to one of the first two options. The G[op] proposal could be thought of as one approach to the first option. Note also that this option can be turned into a generic list all of the eigenstates function by choosing a test that every possible eigenstate is guaranteed to pass; as such, it would be a very small step from this sort of threshing function to a public .eigenstates method - e.g., $j.eigenstates :where { ... } (to add optional threshing capabilities to a list of eigenstates function) or * G~~ $j (to use a thresher to retrieve all of the eigenstates). The infix:where (junction, Code -- junction) proposal that I made earlier is an example of the second option. This option has the advantage that it preserves as much of the junction's internal structure (e.g., composite junctions) as possible, in case said structure may prove useful later on. (I'm a big fan of not throwing anything away until you're sure that you don't need it anymore.) The downside is that if you want a list of the eigenstates that passed the test, this is only an intermediate step to getting it: you still have to figure out how to extract a list of eigenstates from the threshed junction. The third option has the benefit of letting you handle if so if not without having to thresh twice, once for the wheat and again for the chaff. OTOH, it's bound to be more complicated to work with, and is overkill if you only care about one of the outcomes. I have no syntax proposals at this time. Note further that these aren't necessarily mutually exclusive options: TIMTOWTDI. I prefer the ones that use some form of where; but that's just because those approaches feel intuitive to me. The canonical example of quantum computing is using it to factor huge numbers to break an encryption system. There you divide the huge number by the superposition of all of the possible factors, and then take the eigenstate of the factors that divide evenly to eliminate all of the huge pile of potential factors that did not divide evenly. Without being able to take the eigenstate, the boolean answer yes, any(1..n-1) divides n is of very little value. Right. Something like: any(2 ..^ $n).eigenstates :where($n mod $_ == 0) or: ( any(2 ..^ $n) where { $n mod $_ == 0 } ).eigenstates ...might be ways to get a list of the factors of $n. (I'm not sure how this would be done with junctions and the proposed grep metaoperator - although I _can_ see how to do it with _just_ the metaoperator, or with just a grep method. But that's list manipulation, not junctive processing.) Of course, evaluating this code could be a massive headache without a quantum processor. I'm sure that one _could_ come up with a Set-based approach to doing this; it might even be fairly easy to do. But again, TIMTOWTDI. Perl has never been about trying to come up with an ideal approach and then forcing everyone to use it - that would be LISP, among others. Telling people that they must use Sets instead of junctions in cases such as this runs counter to the spirit of Perl. -- Jonathan Dataweaver Lang
Re: On Junctions
What I see here is that there is a tendency to want to think about, and operate on, the eigenstates as a Set, but this seems to destroy the single value impersonation of the Junction. Further, if one ever calls .!eigenstates() on a Junction, then you have really bollox'd your code up, as then this code fails if the value you thought was a Junction happens to be, actually, just a single value! (Unless .!eigenstates() is defined on Object, and returns a Set of self...) I think what is needed is a single value threshing function, which can be applied to, well, single values. Such a function would take a value and a predicate, and if the predicate applied to the value is true, returns the value, else it returns... nothing. If such a function were applied to a Junction, then the result would be a Junction of just those those eigenstates that passed this function. The nothings would not end up contributing to the Junction. Now, I'm not sure I know how to return nothing in Perl6, but I'll guess that undef can serve the purpose, since I can't think of a useful use of undef as part of a Junction. sub suchthat(Any $v, predicate) { predicate($v) ?? $v !! undef } So now: $a = 1|2|3|4|5 say suchthat($a, odd) 1|3|5 $b = 12345 say suchthat($a, odd) 135 And in the poker example: @p = 1|11, 2, 1|11; @d = 1|11, 3, 1|11; $pv = suchthat([+] @p, {$_ = 21}) $dv = suchthat([+] @d, {$_ = 21}) if $pv and (!$dv or $pv $dv) { say 'p wins!' }; - MtnViewMark Mark Lentczner http://www.ozonehouse.com/mark/ m...@glyphic.com
Re: On Junctions
I stand corrected. That said: with the eigenstates method now private, it is now quite difficult to get a list of the eigenstates of the above expression. Yes, that's a concern. Most of the interesting junction-based algorithms I've developed in the past rely on two facilities: the ability to extract eigenstates, and the ability to thresh a junction: to determine which eigenstates caused a boolean expression involving the junction to be true. However, I suspect that if these two capabilities prove to be all(not easy, very useful) in Perl 6, there will soon be a module that facilitates them. ;-) Damian
Re: On Sets (Was: Re: On Junctions)
Daniel Ruoso wrote: The thing is that junctions are so cool that people like to use it for more things than it's really usefull (overseeing that junctions are too much powerfull for that uses, meaning it will lead to unexpected behaviors at some point). What are the general boundaries for junctions? We know that engineering type problems should be solved using floating point variables rather than integers (although it is probable that an integer solution probably would be possible - it would be excessively complicated). Perhaps, it might help to see some more examples of how junctions should be used? Regards, Richard
Re: On Junctions
Em Sáb, 2009-03-28 às 16:17 +1100, Damian Conway escreveu: Nested heterogeneous junctions are extremely useful. For example, the common factors of two numbers ($x and $y) are the eigenstates of: all( any( factors($x) ), any( factors($y) ) ) I think that's the exact case where we should be using sets instead... my $common_factors = factors($x) ∩ factors($y) Assuming we have... multi infix:∩(List @a, List @b -- Set) {...} multi infix:∩(Set @a, Set @b -- Set) {...} ... and variants ... But the semantics of sets are still somewhat blurry... there are some possibilities: 1) Sets are in the same level as junctions, but have no collapsing and allow you to get its values. The problem is if it autothreads on method calls or not... It also makes $a $b confuse... 2) Set ~~ Any, and all the inteligence is made implementing multis, it has the disadvantage that new operators will need to have explicit implementations in order to get Set DWIMmery... I have been unsure about that, but lately I'm mostly thinking option 2 is the sanest, which means we only get as much DWIMmery as explicitly implemented (which may or may not be a good idea). daniel
Re: On Sets (Was: Re: On Junctions)
Em Sáb, 2009-03-28 às 13:36 +0300, Richard Hainsworth escreveu: Daniel Ruoso wrote: The thing is that junctions are so cool that people like to use it for more things than it's really usefull (overseeing that junctions are too much powerfull for that uses, meaning it will lead to unexpected behaviors at some point). What are the general boundaries for junctions? Junctions are superposition of values with a given collapsing type. The most important aspect of junctions is that they are a singular value, which means that they are transparent to the code using it. You always use it as a singular value, and that's what keep its semantics sane. The boundary is where you try to use a junction as a plural value, and that's where the semantics get weird... Perhaps, it might help to see some more examples of how junctions should be used? They should be used as a singular value... which means that the blackjack example is only a good example for junctions, as far as to know if the user has busted. my @hand = 1|11, 9, 1|11; my $sum = [+] @hand; if ($sum = 21) { # valid game } else { # busted! } The semantic is sane that way because it doesn't make a difference if there is a junction or not... my @hand = 6, 9, 6; my $sum = [+] @hand; if ($sum = 21) { # valid game } else { # busted! } But even to compare two hands it gets weird... my @a = 1|11, 9, 1|11; my @b = 6,9,6; my $pa = [+] @a; my $pb = [+] @b; if ($pa = 21 $pb = 21) { if ($pa $pb) { # B0RK3D } } That happens because $pa and $pb are a singular value, and that's how junctions work... The blackjack program is an example for sets, not junctions. Now, what are junctions good for? They're good for situation where it's collapsed nearby, which means, it is used in boolean context soon enough. Or where you know it's not going to cause the confusion as in the above code snippet. Sets can provide the cool DWIMmery junction provides for the blackjack case and still provide sane semantics for you to get its compound values. daniel
Re: On Junctions
On Fri, Mar 27, 2009 at 05:49:02PM -0400, Henry Baragar wrote: I believe that there are hands where $p = 15|26 which would not beat a hand where $d = 17. I believe that the correct way to calculate the value of the hand is: my $p = ([+] @p).map{.eigenstates}.grep{$_ 21}.max; Since the result of [+] is a scalar we don't need to 'map' it. Assuming that .eigenstates exists it would then be my $p = ([+] @p).eigenstates.grep({ $_ 21 }).max Pm
Re: On Junctions
Daniel Ruoso wrote: But the semantics of sets are still somewhat blurry... there are some possibilities: 1) Sets are in the same level as junctions, but have no collapsing and allow you to get its values. The problem is if it autothreads on method calls or not... It also makes $a $b confuse... 2) Set ~~ Any, and all the inteligence is made implementing multis, it has the disadvantage that new operators will need to have explicit implementations in order to get Set DWIMmery... I have been unsure about that, but lately I'm mostly thinking option 2 is the sanest, which means we only get as much DWIMmery as explicitly implemented (which may or may not be a good idea). My understanding is that Set operates on the same level as Hash and List - indeed, a Set could be thought of as a Hash that only cares about the keys but not the values, and has a few additional methods (i.e., the set operations). That is, a junction is an item with an indeterminate value; but a Set is a collection of values in the same way that a hash is. And the proper sigil for a Set is %, not $. -- Jonathan Dataweaver Lang
Re: On Sets (Was: Re: On Junctions)
HaloO, On Friday, 27. March 2009 12:57:49 Daniel Ruoso wrote: 1 - multi infix:+(Set $set, Num $a) This would return another set, with each value of $set summed with $a. I think that this mixed case should numify the set to the number of elements to comply with array semantics. infix:+ should remain a numeric operator and numify other operant types. This operator orientation is a strong feature of Perl 6 and should not be diluted by overloads with non-numeric meanings. 2 - multi infix:+(Set $a, Set $b) This would return another set, with $a.values X+ $b.values, already removing duplicated values, as expected from a set. Even the homogeneous case should adhere to numeric semantics. Set operations are with parens. So disjoint union creation is (+). We could try to get a meta parens so that (X+) is conceivably auto-generated. OTOH it collides with (+) visually. Regards, TSa. -- The unavoidable price of reliability is simplicity -- C.A.R. Hoare Simplicity does not precede complexity, but follows it. -- A.J. Perlis 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan
Re: On Junctions
Patrick R. Michaud wrote: On Fri, Mar 27, 2009 at 05:49:02PM -0400, Henry Baragar wrote: I believe that there are hands where $p = 15|26 which would not beat a hand where $d = 17. I believe that the correct way to calculate the value of the hand is: my $p = ([+] @p).map{.eigenstates}.grep{$_ 21}.max; Since the result of [+] is a scalar we don't need to 'map' it. Assuming that .eigenstates exists it would then be my $p = ([+] @p).eigenstates.grep({ $_ 21 }).max Argh... the multiple personalities of the junction caused me to forget that there is only one scalar! HB Pm
Re: On Sets (Was: Re: On Junctions)
On Sat, Mar 28, 2009 at 6:39 AM, Daniel Ruoso dan...@ruoso.com wrote: Em Sáb, 2009-03-28 às 13:36 +0300, Richard Hainsworth escreveu: Daniel Ruoso wrote: The thing is that junctions are so cool that people like to use it for more things than it's really usefull (overseeing that junctions are too much powerfull for that uses, meaning it will lead to unexpected behaviors at some point). What are the general boundaries for junctions? Junctions are superposition of values with a given collapsing type. The most important aspect of junctions is that they are a singular value, which means that they are transparent to the code using it. You always use it as a singular value, and that's what keep its semantics sane. Closely related to this is that junctions autothread. If you type in foo($a | $b), it will be processed exactly as if you had typed foo($a) | foo($b) - that is, it will call foo twice, once for $a and once for $b, and it won't care which order it uses. And this is true whether or not you know that a junction is involved. Given 'foo($j)', foo will be called once if $j isn't a junction, and will be called multiple times if $j is a junction. If you were dealing with a Set instead, you'd need to make use of 'map' and/or hyperoperators to achieve a similar result. -- Jonathan Dataweaver Lang
Re: On Sets (Was: Re: On Junctions)
Thomas Sandlaß wrote: Set operations are with parens. Which Synopsis is this in? -- Jonathan Dataweaver Lang
Re: On Sets (Was: Re: On Junctions)
Daniel Ruoso wrote: But even to compare two hands it gets weird... my @a = 1|11, 9, 1|11; my @b = 6,9,6; my $pa = [+] @a; my $pb = [+] @b; if ($pa = 21 $pb = 21) { if ($pa $pb) { # B0RK3D } } That happens because $pa and $pb are a singular value, and that's how junctions work... The blackjack program is an example for sets, not junctions. The blackjack program is an excellent example for junctions (and not so good for sets, IMHO). The problem in the example above is that the calculation of the value of a hand was not completed. The complete calculation is as follows: my $pa = ([+] @a).eigenstates.grep{$_ 21}.max If the result is undef, then the @a hand is a bust, and comparing $pa to a similarly calculated $pb is sane. Henry daniel
Re: On Sets (Was: Re: On Junctions)
Henry Baragar wrote: The blackjack program is an excellent example for junctions (and not so good for sets, IMHO). The problem in the example above is that the calculation of the value of a hand was not completed. The complete calculation is as follows: my $pa = ([+] @a).eigenstates.grep{$_ 21}.max Per the recent change to the synopses, eigenstates is now a private method, rendering the above code invalid. -- Jonathan Dataweaver Lang
On Junctions
The following arose out of a discussion on #perl6. Junctions are new and different from anything I have encountered, but I cant get rid of the feeling that there needs to be some more flexibility in their use to make them a common programming tool. Background: Imagine a hand of cards. Cards may be Ace, Two, Three. Ace having either the values 1 or 11, depending on context, the other cards their face value. Sums of a hand over 21 are invalid. Hands with multiple junctions become interesting, eg., p: Ace, Two, Ace d: Ace, Three, Ace Given that Ace has a value of 1 or 11 depending on context, it would seem natural to use a junction. Hence the two hands can be expressed as: @p = 1|11, 2, 1|11; @d = 1|11, 3, 1|11; If we use [+] to add these, we get $p = [+] @p; say $p.perl; # any(any(4,14),any(14,24)) $d = [+] @d; say $d.perl; #any(any(5,15),any(15,25)) Since the values of 24 25 are greater than 21, they must be eliminated from consideration. What we want is for hand @d to beat hand @p because 15 14 On #perl6, rouso, masak and moritz_ explained that I am incorrectly thinking about junctions as sets and that for this task I should be using another perl idiom, namely lists. Something like: moritz_ rakudo: ([1,11], 3, [1,11]).reduce({@($^a) X+ @($^b)}) p6eval rakudo bb22e0: RESULT«[5, 15, 15, 25]» Then the out-of-limit values (in the above case 25) can be stripped off using grep, viz., # here we have ([1,11],3,[1,11]) instead of (1|11, 3, 1|11) my @dlist = grep { $_ 21 } ([1,11], 3, [1,11]).reduce({@($^a) X+ @($^b)}); Then the two lists (do the same for @p) can be compared by a junction comparison of the form if any(@plist) all(@dlist) { say 'p wins' }; The problem is not just that [+] @p produces a junction with undesired (21) eigenstates, but that the [+] @d produces a junction of the form any(any(5,15),any(15,25)) which should collapse to any(5,15,25) whereas we want a junction of the form all(5,15,25) After the #perl6 conversation, I thought some more. A junction is a neat way of expressing the hand, but the junction needs to be converted to a list to do some processing, and then the lists are compared using junctions. I think (I might be wrong) that the conversion from a junction to a list is specified by the .eigenstates method, but it doesn't seem to completely flatten a junction yet - it produces the any(any(4,14),any(14,24)) output shown above. So my questions to the language list are: a) Am I trying to fit a square peg in a round hole by applying junctions to this sort of problem? If so, would it be possible to explain what the limits are to the junction approach, or another way of expressing this question: what sort of problems should junctions be applied to? b) Why would it be wrong to have a method for eliminating eigenstates from a junction? (The answer to this might naturally arise out of the answer to a). However, ... In a wider context, I would conjecture that some algorithms to which junctions could be applied would be optimised if some states could be eliminated, a bit like tree-pruning optimisations that eliminate paths which can never produce a correct answer. Consequently, providing a filtering method would increase the usefulness of the junction as a programming tool. Perhaps $new-junction = $old-junction.grep({ $_ = 21 }); # not sure if the parens are needed here c) On junction algebra, am I wrong or is always true that a junction of the form any('x','y','z', any('foo','bar'), 1, 2, 3) should collapse to any('x','y','z','foo','bar',1,2,3) In other words, if an 'any' junction is contained in an outer 'any', the inner 'any' can be factored out? This would eliminate the nested junctions produced by .eigenstates d) Am I right in thinking this is also true for nested 'all' junctions? viz. all(1,2,3,all('foo', 'bar')) collapses to all(1,2,3,'foo','bar') e) Conjecture: This true of all junction types, eg., junc(..., junc(...)) == junc(..., ...) f) Would it be possible to have a means to coerce an 'any' junction into an 'all' junction or vice versa? eg. my $old-junction = 1|2|3; my $new-junction = all{$old-junction}; say $old-junction.perl # all(1,2,3) Using () creates a new junction all(any(1,2,3)) {} are undefined for junctions. If my suggestions prove acceptable, then for my problem I would have: # @p @d get defined as arrays of junctions, eg. my @p=1|11,2,1|11; my @d=1|11,3,1|11; #later my $p = ([+] @p).grep { $_ 21 }; my $d = ([+] @d).grep { $_ 21 }; if $p all{$d} { say 'p wins' } else { say 'd wins' }; Richard (finanalyst)
On Sets (Was: Re: On Junctions)
Em Sex, 2009-03-27 às 13:36 +0300, Richard Hainsworth escreveu: On #perl6, rouso, masak and moritz_ explained that I am incorrectly thinking about junctions as sets and that for this task I should be using another perl idiom, namely lists. Sorry for not taking each individual point on your mail, but I think this basically narrows down to the fact that we need some more definitions of what kinds of things we would do with sets. The thing is that junctions are so cool that people like to use it for more things than it's really usefull (overseeing that junctions are too much powerfull for that uses, meaning it will lead to unexpected behaviors at some point). So I get that we do need some cool support for sets as well, I mean... no collapsing, no autothreading... but maybe some specific behaviors... taking the blackjack example... # using the set function as illustration only... my @hand = set(1,11),3,set(1,11); my $sum = [+] @hand; This operation could use some magic so $sum could become set(5,15,25) Where it doesn't autothread, nor collapses... but it still provides the DWIMmery people like so much in junctions... So... which magic happened here? 1 - multi infix:+(Set $set, Num $a) This would return another set, with each value of $set summed with $a. 2 - multi infix:+(Set $a, Set $b) This would return another set, with $a.values X+ $b.values, already removing duplicated values, as expected from a set. So... what do you think? daniel
Re: On Sets (Was: Re: On Junctions)
Em Sex, 2009-03-27 às 08:57 -0300, Daniel Ruoso escreveu: So I get that we do need some cool support for sets as well, I mean... no collapsing, no autothreading... but maybe some specific behaviors... As an aditional idea... multi infix:⋃(Set $a, Set $b) {...} multi infix:⋂(Set $a, Set $b) {...} ...as well as the rest of the set theory... daniel
Re: On Sets (Was: Re: On Junctions)
From a high-level perspective, the blackjack example seems perfect for junctions. An Ace isn't a set of values - its one or the other at a time. It seems to me if you can't make it work with junctions - f you have to use sets instead - then there's something wrong with the implementation of junctions. On 3/27/09, Daniel Ruoso dan...@ruoso.com wrote: Em Sex, 2009-03-27 às 08:57 -0300, Daniel Ruoso escreveu: So I get that we do need some cool support for sets as well, I mean... no collapsing, no autothreading... but maybe some specific behaviors... As an aditional idea... multi infix:⋃(Set $a, Set $b) {...} multi infix:⋂(Set $a, Set $b) {...} ...as well as the rest of the set theory... daniel -- Sent from my mobile device Mark J. Reed markjr...@gmail.com
Re: On Sets (Was: Re: On Junctions)
Em Sex, 2009-03-27 às 09:17 -0400, Mark J. Reed escreveu: From a high-level perspective, the blackjack example seems perfect for junctions. An Ace isn't a set of values - its one or the other at a time. It seems to me if you can't make it work with junctions - f you have to use sets instead - then there's something wrong with the implementation of junctions. It would be a junction if the only question was is it bigger than 21?... but that is not the case, it looks more like... Given S as the set of possible sums, Given V as a subset of S where 21 Given I as a subset of S where 21 If V is empty, Define X as the minimum value of I Else, Define X as the maximum value in V Which really looks like set operations... daniel
Re: On Sets (Was: Re: On Junctions)
Mark J. Reed wrote: From a high-level perspective, the blackjack example seems perfect for junctions. An Ace isn't a set of values - its one or the other at a time. It seems to me if you can't make it work with junctions - f you have to use sets instead - then there's something wrong with the implementation of junctions. That seems as naiive as saying regular expressions are for parsing text, and if you can't parse XML with regular expressions, there's something wrong with them . Leaving aside that Perl 6 regexes do parse XML ;-), we could ask ourselves why junctions aren't suited. The answer is that an any() junction represents just what it says - a conjunction of *any* values, not some of the any values. The example would perfectly work if there was nothing to filter out. You'd need 'some-of-any' junction here, which we don't support. Cheers, Moritz -- Moritz Lenz http://perlgeek.de/ | http://perl-6.de/ | http://sudokugarden.de/
Re: On Sets (Was: Re: On Junctions)
On Fri, Mar 27, 2009 at 10:27 AM, Moritz Lenz ml...@physik.uni-wuerzburg.de wrote: Mark J. Reed wrote: From a high-level perspective, the blackjack example seems perfect for junctions. An Ace isn't a set of values - its one or the other at a time. It seems to me if you can't make it work with junctions - f you have to use sets instead - then there's something wrong with the implementation of junctions. That seems as naiive as saying regular expressions are for parsing text, and if you can't parse XML with regular expressions, there's something wrong with them . Well, I was being intentionally naive. As I said, looking down from above. In thinking about examples for explaining junctions, this one seems a natural fit. Leaving aside that Perl 6 regexes do parse XML ;-) So do Perl 5 ones - since they're not true formal regexes, but have more power to e.g. match balanced tags. Plus of course you wouldn't normally try to write one regex to match an XML document; there'd be wrapper logic. Now if you actually parse XML that way, you're being quite silly. It's far from the best approach. But while maybe junctions aren't the best approach to the Blackjack problem, either, it seems less clear to me. Maybe that's just because I have less experience with junctions. The answer is that an any() junction represents just what it says - a conjunction of *any* values,not some of the any values. The example would perfectly work if there was nothing to filter out. You'd need 'some-of-any' junction here, which we don't support. So at the moment you have to explicitly extract the eigenstates you're interested in, and then construct new junctions from them. Something like this: some($d) 21 some($p) 21 any(grep { $_ 21 } $d.eigenstates}) all(grep { $_ 21 } $p.eigenstates) But it still seems that junctions let you do this more cleanly than sets. Or maybe P6 Sets are more powerful than I think? Given two junctions $d and $p, just adding $d + $p gives you all the possible sums of the eigenstates. Given two sets D and P, is there an equally simple op to generate { d + p : d ∈ D, p ∈ } ? -- Mark J. Reed markjr...@gmail.com
Re: On Sets (Was: Re: On Junctions)
On Fri, Mar 27, 2009 at 11:45 AM, Mark J. Reed markjr...@gmail.com wrote: Given two junctions $d and $p, just adding $d + $p gives you all the possible sums of the eigenstates. Given two sets D and P, is there an equally simple op to generate { d + p : d ∈ D, p ∈ } ? Dropped a P there - should be { d + p : d ∈ D, p ∈ P } -- Mark J. Reed markjr...@gmail.com
Re: On Junctions
Richard Hainsworth wrote: The following arose out of a discussion on #perl6. Junctions are new and different from anything I have encountered, but I cant get rid of the feeling that there needs to be some more flexibility in their use to make them a common programming tool. I strongly agree with you, but Larry has repeatedly said that he wants to view Junctions as lexical sugar rather than as a powerful programming tool. So I'm thinking that we'll need to experiment with modules before anything gets admitted to the core language. If my suggestions prove acceptable, then for my problem I would have: # @p @d get defined as arrays of junctions, eg. my @p=1|11,2,1|11; my @d=1|11,3,1|11; #later my $p = ([+] @p).grep { $_ 21 }; my $d = ([+] @d).grep { $_ 21 }; if $p all{$d} { say 'p wins' } else { say 'd wins' }; I think that the all{..} notation is a little too subtle, and somewhat clumsy (what if there are one or none junctions in $d? do you want to splat them all?). The way I'd view this (before optimization) is: my $p = (reverse 1..21).first: { $_ == [+] @p }; my $d = (reverse 1..21).first: { $_ == [+] @d }; if! $p{ say player bust } elsif ! $d{ say dealer bust } elsif $p $d { say player wins } else { say dealer wins } If this is the structure of the problem, the question then becomes how to move from this brute force implementation to something more elegant (analytical). I discuss this on http://dave.whipp.name/sw/perl6/perl6_xmas_2008.html. I've revised my ideas a little since then (by proposing a more general grep metaoperator G[op] that has applicability beyond junctions) but the basic concepts mesh with yours, I think.
Re: On Junctions
On Fri, Mar 27, 2009 at 10:39 AM, Dave Whipp d...@dave.whipp.name wrote: Richard Hainsworth wrote: The following arose out of a discussion on #perl6. Junctions are new and different from anything I have encountered, but I cant get rid of the feeling that there needs to be some more flexibility in their use to make them a common programming tool. I strongly agree with you, but Larry has repeatedly said that he wants to view Junctions as lexical sugar rather than as a powerful programming tool. So I'm thinking that we'll need to experiment with modules before anything gets admitted to the core language. Maybe you could have something like a filter function that takes a junction and a test condition and returns a junction of those eigenstates from the original one that passed the test. You could then handle the Blackjack problem by saying something to the effect of: $p = [+] @p; $d = [+] @d; if $p = 21 { # Could the total be 21 or less? $p where= { $_ = 21 } #[ infix:where filters the junction according to the given criteria. ] if $p $d { say you won! } } else { say you went over. } -- Jonathan Dataweaver Lang
Re: On Junctions
Richard Hainsworth wrote: The following arose out of a discussion on #perl6. Junctions are new and different from anything I have encountered, but I cant get rid of the feeling that there needs to be some more flexibility in their use to make them a common programming tool. Background: Imagine a hand of cards. Cards may be Ace, Two, Three. Ace having either the values 1 or 11, depending on context, the other cards their face value. Sums of a hand over 21 are invalid. Hands with multiple junctions become interesting, eg., p: Ace, Two, Ace d: Ace, Three, Ace Given that Ace has a value of 1 or 11 depending on context, it would seem natural to use a junction. Hence the two hands can be expressed as: @p = 1|11, 2, 1|11; @d = 1|11, 3, 1|11; If we use [+] to add these, we get $p = [+] @p; say $p.perl; # any(any(4,14),any(14,24)) $d = [+] @d; say $d.perl; #any(any(5,15),any(15,25)) Since the values of 24 25 are greater than 21, they must be eliminated from consideration. What we want is for hand @d to beat hand @p because 15 14 On #perl6, rouso, masak and moritz_ explained that I am incorrectly thinking about junctions as sets and that for this task I should be using another perl idiom, namely lists. Something like: moritz_ rakudo: ([1,11], 3, [1,11]).reduce({@($^a) X+ @($^b)}) p6eval rakudo bb22e0: RESULT«[5, 15, 15, 25]» Then the out-of-limit values (in the above case 25) can be stripped off using grep, viz., # here we have ([1,11],3,[1,11]) instead of (1|11, 3, 1|11) my @dlist = grep { $_ 21 } ([1,11], 3, [1,11]).reduce({@($^a) X+ @($^b)}); Then the two lists (do the same for @p) can be compared by a junction comparison of the form if any(@plist) all(@dlist) { say 'p wins' }; The problem is not just that [+] @p produces a junction with undesired (21) eigenstates, but that the [+] @d produces a junction of the form any(any(5,15),any(15,25)) which should collapse to any(5,15,25) whereas we want a junction of the form all(5,15,25) After the #perl6 conversation, I thought some more. A junction is a neat way of expressing the hand, but the junction needs to be converted to a list to do some processing, and then the lists are compared using junctions. I think (I might be wrong) that the conversion from a junction to a list is specified by the .eigenstates method, but it doesn't seem to completely flatten a junction yet - it produces the any(any(4,14),any(14,24)) output shown above. So my questions to the language list are: a) Am I trying to fit a square peg in a round hole by applying junctions to this sort of problem? If so, would it be possible to explain what the limits are to the junction approach, or another way of expressing this question: what sort of problems should junctions be applied to? b) Why would it be wrong to have a method for eliminating eigenstates from a junction? (The answer to this might naturally arise out of the answer to a). However, ... In a wider context, I would conjecture that some algorithms to which junctions could be applied would be optimised if some states could be eliminated, a bit like tree-pruning optimisations that eliminate paths which can never produce a correct answer. Consequently, providing a filtering method would increase the usefulness of the junction as a programming tool. Perhaps $new-junction = $old-junction.grep({ $_ = 21 }); # not sure if the parens are needed here c) On junction algebra, am I wrong or is always true that a junction of the form any('x','y','z', any('foo','bar'), 1, 2, 3) should collapse to any('x','y','z','foo','bar',1,2,3) In other words, if an 'any' junction is contained in an outer 'any', the inner 'any' can be factored out? This would eliminate the nested junctions produced by .eigenstates d) Am I right in thinking this is also true for nested 'all' junctions? viz. all(1,2,3,all('foo', 'bar')) collapses to all(1,2,3,'foo','bar') e) Conjecture: This true of all junction types, eg., junc(..., junc(...)) == junc(..., ...) f) Would it be possible to have a means to coerce an 'any' junction into an 'all' junction or vice versa? eg. my $old-junction = 1|2|3; my $new-junction = all{$old-junction}; say $old-junction.perl # all(1,2,3) Using () creates a new junction all(any(1,2,3)) {} are undefined for junctions. If my suggestions prove acceptable, then for my problem I would have: # @p @d get defined as arrays of junctions, eg. my @p=1|11,2,1|11; my @d=1|11,3,1|11; #later my $p = ([+] @p).grep { $_ 21 }; my $d = ([+] @d).grep { $_ 21 }; if $p all{$d} { say 'p wins' } else { say 'd wins' }; I believe that there are hands where $p = 15|26 which would not beat a hand where $d = 17. I believe that the correct way to calculate the value of the hand is: my $p = ([+] @p).map{.eigenstates}.grep{$_ 21}.max; which is exactly how I do it when I am playing Blackjack. Put another way, the value of a blackjack hand is deterministic and sane, and you must get rid
Re: On Junctions
[I’d been planning to put this suggestion on hold until the spec is sufficiently complete for me to attempt to implement it as a module. But people are discussing this again, so maybe it's not just me. I apologize if I appear to be beating a dead horse...] Jon Lang wrote: Maybe you could have something like a filter function yes, but that takes a junction and a test condition and returns a junction of those eigenstates from the original one that passed the test. But why is this a useful thing to do? I think that you're proposing, for compound junctions: ok any( 1|2, 12, 5|15, 515 ) where { $_ 10 } === any( 1|2, 12, 5|15 ) To me, it still feels like you're thinking of a junction as a set of values, and inventing an operator specifically for the purpose of messing with those values. I do not see values of a junction as a meaningful user-level concept. I prefer to turn the problem around, and suggest a different operator, motivated by a different issue, and then apply that operator to junctions. Consider this statement: say (0..Inf).grep: { $_ 10 }; I would expect it to take infinite time to complete (or else fail quickly). It would be wrong to expect perl to figure out the correct answer analytically, because that is impossible in the general case of an arbitrary code block. So I instead propose an operator-based grep: say 0..inf G[] 10; [0..9] This “grep metaoperator” can be expected to analytically determine the result (of grepping an infinite list) in finite time. It might also be used to avoid curlies for simple greps: say @lines G~~ /foo/; The operator exists to filter infinite lists in finite time. But it also solves the junction problem: say (-Inf .. Inf) G== 3|4; [3,4] say ^Int G== 3|4; ## assuming ^Int means “any Int value” [3,4] $score = [+] 1|11, 1|11, 1+11, 1+11, 4; say max( 1..21 G== $score ) // bust; 18
Re: On Junctions
Dave Whipp wrote: [I’d been planning to put this suggestion on hold until the spec is sufficiently complete for me to attempt to implement it as a module. But people are discussing this again, so maybe it's not just me. I apologize if I appear to be beating a dead horse...] Jon Lang wrote: Maybe you could have something like a filter function yes, but that takes a junction and a test condition and returns a junction of those eigenstates from the original one that passed the test. But why is this a useful thing to do? I think that you're proposing, for compound junctions: ok any( 1|2, 12, 5|15, 515 ) where { $_ 10 } === any( 1|2, 12, 5|15 ) ...not really, no. The way I was looking at it, the above expression is ultimately a junction of the values 1, 2, 5, and 15; no matter how compounded the junction is, these would be its eigenstates. Since 15 would fail the test, anything having to do with it would be filtered out. Exactly how that would work with a compound junction, I'm not sure; as I said, I was thinking of the eigenstates as ordinary items, not nested junctions. But yes, I _was_ suggesting something that transforms one junction into another. That said, I'm also leery of compound junctions. Please tell me the difference between: any( 1|2 ) ...and: any( 1, 2 ) If there is no difference, then: any( 1|2, 12, 5|15, 515 ) eqv any( 1, 2, 12, 5, 15, 515 ) For that matter, I'm not seeing a difference between: any( 12 ) # any of all of (1, 2) ...and: any( 1, 2 ) # any of (1, 2) If I'm not mistaken on these matters, that means that: any( 1|2, 12, 5|15, 515 ) eqv any(1, 2, 5, 15) And I expect that similar rules hold for other compound junctions. In short, I won't be surprised if all compound junctions can flatten into equivalent simple junctions. To me, it still feels like you're thinking of a junction as a set of values, and inventing an operator specifically for the purpose of messing with those values. I do not see values of a junction as a meaningful user-level concept. I'm pretty sure that Larry agrees with you here, seeing as how his latest revision concerning junctions makes direct access to a junction's eigenstates very difficult to arrange. I prefer to turn the problem around, and suggest a different operator, motivated by a different issue, and then apply that operator to junctions. Consider this statement: say (0..Inf).grep: { $_ 10 }; I would expect it to take infinite time to complete (or else fail quickly). It would be wrong to expect perl to figure out the correct answer analytically, because that is impossible in the general case of an arbitrary code block. So I instead propose an operator-based grep: say 0..inf G[] 10; [0..9] This “grep metaoperator” can be expected to analytically determine the result (of grepping an infinite list) in finite time. It might also be used to avoid curlies for simple greps: say @lines G~~ /foo/; The operator exists to filter infinite lists in finite time. But it also solves the junction problem: say (-Inf .. Inf) G== 3|4; [3,4] And how would it handle a compound junction (assuming they exist)? That is: say (-Inf .. Inf) G== any(1|2, 12, 5|15, 515); ??? $score = [+] 1|11, 1|11, 1+11, 1+11, 4; I assume you meant: $score = [+] 1|11, 1|11, 4; say max( 1..21 G== $score ) // bust; 18 ...and the answer to that would be 16, right? -- Jonathan Dataweaver Lang
Re: On Junctions
Jon Lang wrote: For that matter, I'm not seeing a difference between: any( 12 ) # any of all of (1, 2) ...and: any( 1, 2 ) # any of (1, 2) Those two are very different. any(1,2) == 2 is true any(12) == 2 is false Nested heterogeneous junctions are extremely useful. For example, the common factors of two numbers ($x and $y) are the eigenstates of: all( any( factors($x) ), any( factors($y) ) ) If I'm not mistaken on these matters, that means that: any( 1|2, 12, 5|15, 515 ) eqv any(1, 2, 5, 15) No. They have equivalent eigenstates, but they are not themselves equivalent. For example, any( 1|2, 12, 5|15, 515 ) compares == to 12; whereas any(1, 2, 5, 15) doesn't. And I expect that similar rules hold for other compound junctions. In short, I won't be surprised if all compound junctions can flatten into equivalent simple junctions. In general, they can't; not without changing their meaning. Damian
Re: On Junctions
Damian Conway wrote: Jon Lang wrote: For that matter, I'm not seeing a difference between: any( 12 ) # any of all of (1, 2) ...and: any( 1, 2 ) # any of (1, 2) Those two are very different. any(1,2) == 2 is true any(12) == 2 is false Nested heterogeneous junctions are extremely useful. For example, the common factors of two numbers ($x and $y) are the eigenstates of: all( any( factors($x) ), any( factors($y) ) ) I stand corrected. That said: with the eigenstates method now private, it is now quite difficult to get a list of the eigenstates of the above expression. -- Jonathan Dataweaver Lang
Re: .perl and other methods on Junctions?
On Wed, Nov 05, 2008 at 11:28:00AM -0800, Larry Wall wrote: But it seems to me that if stringification of a junction returns a correct .perlish syntax, it's probably better to just let that happen lazily, on the assumption someone might want .perl to autothread for some reason, perhaps because .perl performs some kind of useful canonicalization prior to comparison. So I think the actual choice is driven by the fact that Str(Junction) is defined to work like you'd expect .perl to do if .perl did it, which it doesn't... This all works for me, thanks for the clarification! Pm
Re: .perl and other methods on Junctions?
On Tue, Nov 04, 2008 at 01:33:09PM -0600, Patrick R. Michaud wrote: : Consider the code: : : my $x = 3 | 'foo'; : my $y = $x.perl; : : : Does $y end up as a junction of strings or as a single string? I think it may not actually matter much, if subsequent stringification of the junction produces a result with correct Perl syntax. : Asking more directly, does .perl autothread over a Junction? : If .perl does not autothread, then is there some way of knowing : which methods autothread and which do not? I think it would depend entirely on whether the Junction class defined method .perl, or relied on the authothreading implementation triggered by Object recognizing that it was handed a Junction. But it seems to me that if stringification of a junction returns a correct .perlish syntax, it's probably better to just let that happen lazily, on the assumption someone might want .perl to autothread for some reason, perhaps because .perl performs some kind of useful canonicalization prior to comparison. So I think the actual choice is driven by the fact that Str(Junction) is defined to work like you'd expect .perl to do if .perl did it, which it doesn't... : (The question of method autothreading over junctions came up at : the OSCON 2008 hackathon, but I don't know that it was ever : resolved. If it was and I've just forgotten or overlooked the : resolution, I'll be happy to have it pointed out to me.) Well, at the time we thought there might need to be some kind of VAR-like JUNCTION macro to give access to the Junction object, but if the decision is just based on whether Junction defines the method or not, that's not really necessary. And with this semantics, it's also no problem going the other way. If method .junk is defined in Junction, you can still force it to autothread by saying $junction.Object::junk(). Larry
Re: [perl #58302] [BUG] binary junctions of undefs in boolean context fails (21/37)
Patrick R. Michaud wrote: On Mon, Aug 25, 2008 at 12:15:05AM +0200, Moritz Lenz wrote: Larry Wall wrote: I think it would be best if all boolean contexts collapse consistently, and I would consider all of those to be boolean contexts. More precisely, and || are boolean on the left, but not on the right. Very good. As a follow-up for the testers: should ok() expect an Object as its first argument? If so we could say ok 1|2, 'Junction 1|2 is true in boolean context'; Keeping with my general philosophy that I'd like to keep the requirements needed to run Test.pm (and the test suite) as simple as possible, I'd prefer to not require type checking within Test.pm in order for it to work right. Beyond that, if we're testing a Junction in boolean context, I think I would prefer to make that an explicit part of the test itself: ok ?(1|2), 'Junction 1|2 is true in boolean context'; I re-wrote the tests to use that kind of syntax, and add it to the official tests: http://svn.pugscode.org/pugs/t/spec/S03-junctions/boolean-context.t My next step will be to fudge it for rakudo. Cheers, Moritz -- Moritz Lenz http://moritz.faui2k3.org/ | http://perl-6.de/
Re: [perl #58302] [BUG] binary junctions of undefs in boolean context fails (21/37)
Moritz Lenz wrote: Tests 34 to 36 were a bit overcritical: (0|undef say not ok 34) || say not ok 34; (0undef say not ok 35) || say not ok 35; (0^undef say not ok 36) || say not ok 36; but are easily corrected. The rest seem fine to me. Easier said than done. Question to p6l: do and || autothread? Or do they collapse the junction prior to evaluation? (I hope the latter, since I think it's more dwimmy). Also do prefix:? and prefix:! collapse the junction? Cheers, Moritz -- Moritz Lenz http://moritz.faui2k3.org/ | http://perl-6.de/
Re: [perl #58302] [BUG] binary junctions of undefs in boolean context fails (21/37)
On Sun, Aug 24, 2008 at 09:22:25PM +0200, Moritz Lenz wrote: : Moritz Lenz wrote: : Tests 34 to 36 were a bit overcritical: : : (0|undef say not ok 34) || say not ok 34; : (0undef say not ok 35) || say not ok 35; : (0^undef say not ok 36) || say not ok 36; : : but are easily corrected. The rest seem fine to me. : : Easier said than done. : Question to p6l: do and || autothread? Or do they collapse the : junction prior to evaluation? (I hope the latter, since I think it's : more dwimmy). : : Also do prefix:? and prefix:! collapse the junction? I think it would be best if all boolean contexts collapse consistently, and I would consider all of those to be boolean contexts. More precisely, and || are boolean on the left, but not on the right. Interestingly, ? and ?| collapse both sides because they coerce both sides to boolean. Either that, or we make neither side collapse, if someone can come up with a use case for junctional booleans, though I suspect the same purpose can be served by + and +| if you're careful only to feed it 1 or 0. So probably conceptual consistency is better here. Larry
Re: [perl #58302] [BUG] binary junctions of undefs in boolean context fails (21/37)
On Sun, Aug 24, 2008 at 03:00:54PM -0700, Larry Wall wrote: : Question to p6l: do and || autothread? Or do they collapse the : junction prior to evaluation? (I hope the latter, since I think it's : more dwimmy). : : Also do prefix:? and prefix:! collapse the junction? I think it would be best if all boolean contexts collapse consistently, and I would consider all of those to be boolean contexts. More precisely, and || are boolean on the left, but not on the right. Yay! I'm assuming the same holds true for the conditional expression in C?? !!. Thanks, Pm
Re: [perl #58302] [BUG] binary junctions of undefs in boolean context fails (21/37)
Larry Wall wrote: On Sun, Aug 24, 2008 at 09:22:25PM +0200, Moritz Lenz wrote: : Moritz Lenz wrote: : Tests 34 to 36 were a bit overcritical: : : (0|undef say not ok 34) || say not ok 34; : (0undef say not ok 35) || say not ok 35; : (0^undef say not ok 36) || say not ok 36; : : but are easily corrected. The rest seem fine to me. : : Easier said than done. : Question to p6l: do and || autothread? Or do they collapse the : junction prior to evaluation? (I hope the latter, since I think it's : more dwimmy). : : Also do prefix:? and prefix:! collapse the junction? I think it would be best if all boolean contexts collapse consistently, and I would consider all of those to be boolean contexts. More precisely, and || are boolean on the left, but not on the right. Very good. As a follow-up for the testers: should ok() expect an Object as its first argument? If so we could say ok 1|2, 'Junction 1|2 is true in boolean context'; (Which has the nice side effect of not confusing fudge because more tests are executed than expected). Moritz -- Moritz Lenz http://moritz.faui2k3.org/ | http://perl-6.de/
Re: [perl #58302] [BUG] binary junctions of undefs in boolean context fails (21/37)
On Sun, Aug 24, 2008 at 05:05:46PM -0500, Patrick R. Michaud wrote: : On Sun, Aug 24, 2008 at 03:00:54PM -0700, Larry Wall wrote: : : Question to p6l: do and || autothread? Or do they collapse the : : junction prior to evaluation? (I hope the latter, since I think it's : : more dwimmy). : : : : Also do prefix:? and prefix:! collapse the junction? : : I think it would be best if all boolean contexts collapse consistently, : and I would consider all of those to be boolean contexts. More : precisely, and || are boolean on the left, but not on the right. : : Yay! : : I'm assuming the same holds true for the conditional expression : in C?? !!. Indeed. Larry
Re: [perl #58302] [BUG] binary junctions of undefs in boolean context fails (21/37)
On Mon, Aug 25, 2008 at 12:15:05AM +0200, Moritz Lenz wrote: Larry Wall wrote: I think it would be best if all boolean contexts collapse consistently, and I would consider all of those to be boolean contexts. More precisely, and || are boolean on the left, but not on the right. Very good. As a follow-up for the testers: should ok() expect an Object as its first argument? If so we could say ok 1|2, 'Junction 1|2 is true in boolean context'; Keeping with my general philosophy that I'd like to keep the requirements needed to run Test.pm (and the test suite) as simple as possible, I'd prefer to not require type checking within Test.pm in order for it to work right. Beyond that, if we're testing a Junction in boolean context, I think I would prefer to make that an explicit part of the test itself: ok ?(1|2), 'Junction 1|2 is true in boolean context'; Pm
Building Junctions from Junctions
Hi all, I use Perl6::Junction in Perl 5 and recently the author implemented the values method on junctions. I needed this because I sometimes find that I need to do something conceptually similar to this: my $number = any( 0 .. 19 ); while ($number-values) { my $rand int(rand(20)); if ( $number == $random_number ) { # handle some task and discard the number $number = any( grep { $_ != $rand } $number-values ); } } In other words, sometimes I have code which receives a junction and needs to provide a new junction based on the values of the old junction, but with some values removed. How do I do that in Perl 6? I can't see that in the docs. Clearly we don't this to be done destructively as I suspect this will break autothreading, but building new junctions based on old junctions seems reasonable. Cheers, Ovid -- Buy the book - http://www.oreilly.com/catalog/perlhks/ Personal blog- http://publius-ovidius.livejournal.com/ Tech blog- http://use.perl.org/~Ovid/journal/ Official Perl 6 Wiki - http://www.perlfoundation.org/perl6 Official Parrot Wiki - http://www.perlfoundation.org/parrot
Re: Building Junctions from Junctions
I'd say that this ought to be implemented using :v (as in, 'values'; cf. :k, :kv, and :p for lists and hashes): this should let you look at the values within the Junction as if they were merely a list of values, at which point you can construct a new Junction from them. -- Jonathan Dataweaver Lang
Re: Junctions as arguments (Pugs bug)
Ovid wrote: (reversed the message a bit) is 'b', any('a' .. 'h'), 'junctions should work'; This looks like a Test bug; it's doing something like: is 'b', 'a' # not ok is 'b', 'b' # ok is 'b', 'c' # not ok ... If you write: ok 'b' === any('a'..'h') The result is one passing test. That outputs something like the following on my system (Version: 6.2.13 (r14927)) any(VInt 1,VInt 2,VInt 3,VInt 4) any(VRef Scalar:0x2aa80e0) My question is, what is the expected output of say-ing a junction? Should say (1|2|3) randomly print 1, 2, or 3? Should say (123) say 1, then say 2, then say 3? I can understand it going either way (although I'd lean towards what Ovid is expecting), but it would be good to hear what others think before tests are committed. -- package JAPH;use Catalyst qw/-Debug/;($;=JAPH)-config(name = do { $,.=reverse qw[Jonathan tsu rehton lre rekca Rockway][$_].[split //, ;$;]-[$_].q; ;for 1..4;$,=~s;^.;;;$,});$;-setup;
Re: Junctions as arguments (Pugs bug)
On Wed, Dec 20, 2006 at 10:26:41AM -0600, Jonathan Rockway wrote: : Ovid wrote: : (reversed the message a bit) :is 'b', any('a' .. 'h'), 'junctions should work'; : : This looks like a Test bug; it's doing something like: : :is 'b', 'a' # not ok :is 'b', 'b' # ok :is 'b', 'c' # not ok :... : : If you write: : :ok 'b' === any('a'..'h') : : The result is one passing test. : : : That outputs something like the following on my system (Version: 6.2.13 : (r14927)) : :any(VInt 1,VInt 2,VInt 3,VInt 4) :any(VRef Scalar:0x2aa80e0) : : My question is, what is the expected output of say-ing a junction? : Should say (1|2|3) randomly print 1, 2, or 3? Should say (123) : say 1, then say 2, then say 3? : : I can understand it going either way (although I'd lean towards what : Ovid is expecting), but it would be good to hear what others think : before tests are committed. What you're seeing is standard autothreading behavior, which is described in S09, Junctions. To avoid autothreading, a routine must declare itself prepared to handle junctions with an appropriate type signature, and I'm not sure we want to complicate Test to that extent, since it makes it harder to port. Larry
Do junctions support determining interesections of lists
Almost a year ago (2005-04-27), I wrote the list asking a question about junctions. Specifically, the ability to find the intersection, union, etc of a list. my $matches = any( @x_chars ) eq any( @y_chars ); my $match = $matches.pick; all( any() eq any() ); Patrick Michaud offered an infix myeq to let the problem be solved in user space as junctions at that time did not support what I wanted to do. Today I examined the Synopses and found a couple of intriguing things: In Synopsis 3: A junction is a single value that is equivalent to multiple values. And then later on... Junctions are specifically unordered. So if you say for all(@foo) {...} it indicates to the compiler that there is no coupling between loop iterations and they can be run in any order or even in parallel. This implies to me that it is possible to get the values out of a junction without calling a .values method if used in list context. From Synopsis 12: To hyperoperate over the values of a junction you have to explicitly pull out the values: $junction.values».meth(@args); This implies to me that you can still get at the values by explicitly using .values. From Synopsis 9: Some contexts, such as boolean contexts, have special rules for dealing with junctions. In any scalar context not expecting a junction of values, a junction produces automatic parallelization of the algorithm. Ok, so what about a context expecting a junction of values as I think all( any() eq any() ) is expecting? My question today is 2 fold. 1. Where in the synopses would I find the various methods that can be performed on a junction? A. .values B. .pick C. ??? 2. Do the junctions of today support finding the union, intersection, etc without creating your own infix operator? Cheers, Joshua Gatcomb a.k.a. Limbic~Region
Re: Do junctions support determining interesections of lists
On Tue, Apr 04, 2006 at 09:16:23AM -0400, Joshua Gatcomb wrote: : Almost a year ago (2005-04-27), I wrote the list asking a question about : junctions. : Specifically, the ability to find the intersection, union, etc of a list. Junctions are not intended for that use. We have Sets for that now. Junctions are specifically intended to be sets with lazy booleans properties, and those lazy boolean properties interfere with ordinary set semantics. : my $matches = any( @x_chars ) eq any( @y_chars ); : my $match = $matches.pick; : : all( any() eq any() ); Junctions use sets to do their calculations, and you can pull out the set that a particular junction is using, but junctions are primarily intended to tell you whether, not what. And a junction is specifcally not a set, but a set of sets. : Patrick Michaud offered an infix myeq to let the problem be solved in user : space : as junctions at that time did not support what I wanted to do. : : Today I examined the Synopses and found a couple of intriguing things: : : In Synopsis 3: : : A junction is a single value that is equivalent to multiple values. : : And then later on... : : Junctions are specifically unordered. So if you say : : for all(@foo) {...} : : it indicates to the compiler that there is no coupling between loop : iterations and they can be run in any order or even in parallel. : : This implies to me that it is possible to get the values out of a junction : without calling a .values method if used in list context. That is not what is intended there. I believe that particular for is autothreading, not extracting the values. Admittedly the text is not clearly written. To each iteration it appears that there is only one loop value, not a list. For autothreading in general, if the compiler is able to falsify any of the variants, it doesn't need to run that particular autothread at all, even if it would produce side effects. : From Synopsis 12: : : To hyperoperate over the values of a junction you have to explicitly pull : out the values: : : $junction.values».meth(@args); : : This implies to me that you can still get at the values by explicitly using : .values. Yes, but you're really extracting the internal set of the junction while throwing away the extra information that makes the junction not a set. If you want to extract the set from a junction, you can probably just use a coercion $set = $junction as Set; And in fact, merely using one of the set operators probably coerces its arguments to sets, so you can probably say things like any(@foo) (+) any(@bar) which won't be treated any differently from @foo (+) @bar I expect the compiler could just optimize away any() there as noise, and maybe all() too. Probably one() or none() though, since one() is perhaps really a set of sets, while none() is a universal negative, which is difficult to find the enumaration of. But in particular, we'd like to be able to talk about sets of types as Dog|Cat and have the internals autocoerce to Sets of type signatures where junctions make little sense. : From Synopsis 9: : : Some contexts, such as boolean contexts, have special rules for dealing : with junctions. In any scalar context not expecting a junction of values, a : junction produces automatic parallelization of the algorithm. : : Ok, so what about a context expecting a junction of values as I think all( : any() eq any() ) is expecting? I don't think you can do simple set theory that way. Better to use explicit sets. The junctional stuff is really about sets of sets, and we'd be better off keeping a clean separation. Consider that the set of sets: one(@foo) is a proper subset of the any(@foo) set of sets. Junctions are just convenient way to represent simple sets of sets with a single set plus an extra dab of info. : My question today is 2 fold. : : 1. Where in the synopses would I find the various methods that can be : performed on a junction? : A. .values : B. .pick : C. ??? I think .values and .pick are probably just Set operations, and if they work on junctions, it'd be by autocoercion. : 2. Do the junctions of today support finding the union, intersection, etc : without creating your own infix operator? The cabal already decided once (in Portland, I believe) to include the standard set operators and a Set type, as well as ASCII representations like (*) and (+) for the set ops so we don't force anyone to use Unicode prematurely. Unfortunately these have not found their way into the synopses yet, as far as I know. Sorry if this is a bit meandering--jet lag is interfering constructively with my native dimwit... Larry
Re: Do junctions support determining interesections of lists
On the other hand, if junctions really are sets of sets, then maybe it's a mistake to autocoerce junctions to sets by swiping their internal set of values. Arguably any(1,2,3) should coerce not to (1,2,3) but to ( (1), (2), (3), (1,2), (1,3), (2,3), (1,2,3), ) Larry