Re: Do junctions support determining interesections of lists
On 4/4/06, Larry Wall [EMAIL PROTECTED] wrote: On Tue, Apr 04, 2006 at 09:16:23AM -0400, Joshua Gatcomb wrote: Junctions are not intended for that use. We have Sets for that now. Ok. So this will work out of the box if you use the right tool. Cool. 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. Fair enough. For the benefit of everyone following along at home - which of the Synopses should we be following to see how Sets fit into Perl6? Sorry if this is a bit meandering--jet lag is interfering constructively with my native dimwit... No apology necessary. I don't understand everything but I don't need to. I am happy trusting that smarter people than me are working on the problem. Larry Joshua Gatcomb a.k.a. L~R
Re: Set Theory (Was: Do junctions support determining interesections of lists)
On Tue, Apr 04, 2006 at 11:02:55AM -0700, Jonathan Lang wrote: : Will perl6 Sets include set negation and/or a universal set? In : effect, an internal flag that says, this set contains every possible : element _except_ the ones listed? Arguably, that's what none() is. And all() is the only junction that is also a normal enumerated set. The any() junction is the set of sets that would intersect with the corresponding all() set without producing the null set. And the one() junction is the set of sets corresponding to the enumeration of all(). But this is all based on enumerated sets. Oddly missing are any Sets that are defined by rule. That would presumably take closures, though I suppose one can attempt to enumerate the closures that have to hold true and autothread through the calls to those closures... Can Russel be far behind? :-) Larry
Re: Set Theory (Was: Do junctions support determining interesections of lists)
Larry Wall wrote: On Tue, Apr 04, 2006 at 11:02:55AM -0700, Jonathan Lang wrote: : Will perl6 Sets include set negation and/or a universal set? In : effect, an internal flag that says, this set contains every possible : element _except_ the ones listed? Arguably, that's what none() is. ...except that none() is a Junction, not a Set. As such, the same arguments that say that any() and all() aren't suitable for use as Sets apply to none(), don't they? -- Jonathan Dataweaver Lang
Re: Set Theory (Was: Do junctions support determining interesections of lists)
On Tue, Apr 04, 2006 at 11:23:14AM -0700, Jonathan Lang wrote: : Larry Wall wrote: : On Tue, Apr 04, 2006 at 11:02:55AM -0700, Jonathan Lang wrote: : : Will perl6 Sets include set negation and/or a universal set? In : : effect, an internal flag that says, this set contains every possible : : element _except_ the ones listed? : : Arguably, that's what none() is. : : ...except that none() is a Junction, not a Set. As such, the same : arguments that say that any() and all() aren't suitable for use as : Sets apply to none(), don't they? You're confusing the map with the territory. We're trying to decide *how* Junctions are like Sets, not defining them into two different universes. I'm saying that all() is the Junction tha is most like a Set. A none() Junction can be viewed as the specification for an infinite set of sets that do not intersect with the corresponding all() junction. Infinite sets are a bit hard to compute with directly. A one() junction is the spec for a number of sets corresponding to the values of the corresponding all() junction, each of which contains only one element from that set. An any() Junction is all possible subsets not counting the null set. So junctional logic could be defined in terms of set theory, but not in a necessarily computable way. Larry
Re: Set Theory (Was: Do junctions support determining interesections of lists)
2006/4/4, Larry Wall [EMAIL PROTECTED]: But this is all based on enumerated sets. Oddly missing are any Sets that are defined by rule. That would presumably take closures, though I suppose one can attempt to enumerate the closures that have to hold true and autothread through the calls to those closures... Can Russel be far behind? :-) This is in ext/Recurrence: use Recurrence; # all integer numbers $universe = Recurrence.new( closure_next = sub { $_ + 1 }, closure_previous = sub { $_ - 1 }, :is_universe(1) ); # all even integers $even_numbers = Recurrence.new( closure_next = sub { 2 * int( $_ / 2 ) + 2 }, closure_previous = sub { 2 * int( ( $_ - 1 ) / 2 ) }, universe = $universe ); # all odd integers $odd_numbers = $even_numbers.complement; # all non-zero integers $non_zero = Recurrence.new( closure_next =sub ($x) { $x == -1 ?? 1 !! $x + 1 }, closure_previous =sub ($x) { $x == 1 ?? -1 !! $x - 1 }, complement_next = sub ($x) { $x 0 ?? 0 !!Inf }, complement_previous = sub ($x) { $x 0 ?? 0 !! -Inf }, universe = $universe ); - Flavio S. Glock
Re: Set Theory (Was: Do junctions support determining interesections of lists)
Larry Wall wrote: You're confusing the map with the territory. We're trying to decide *how* Junctions are like Sets, not defining them into two different universes. I'm saying that all() is the Junction tha is most like a Set. A none() Junction can be viewed as the specification for an infinite set of sets that do not intersect with the corresponding all() junction. Infinite sets are a bit hard to compute with directly. OK, then; what would be the specification for a _single_ set that contains everything that doesn't intersect with a corresponding all() Junction (the sort of thing that I'd use if I wanted to find the largest subset of A that doesn't intersect with B)? A one() junction is the spec for a number of sets corresponding to the values of the corresponding all() junction, each of which contains only one element from that set. An any() Junction is all possible subsets not counting the null set. Yeah; I got that. -- Jonathan Dataweaver Lang
Re: Do junctions support determining interesections of lists
On 4/4/06, Larry Wall [EMAIL PROTECTED] wrote: 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), ) I don't follow. Why is that the representation of any(1,2,3)? Is this a disjunctive normal form; i.e. is 2 any(1,2,3) equivalent to the test: 2 1 || 2 2 || 2 3 || 2 1 2 2 || ... Or did you have something else in mind? Luke
Fwd: Set Theory (Was: Do junctions support determining interesections of lists)
On 4/4/06, Jonathan Lang [EMAIL PROTECTED] wrote: OK, then; what would be the specification for a _single_ set that contains everything that doesn't intersect with a corresponding all() Junction (the sort of thing that I'd use if I wanted to find the largest subset of A that doesn't intersect with B)? Can't do it. Here's a proof. Suppose you could find a _single_ set that contains everything that doesn't intersect some other set (the complement). Let S be the complement of the empty set. S is not an element of the empty set, so it must be a member of S, which is impossible. Finding the complement of a set assuming some other set is not hard though, simply by using the set difference operator. Luke
Re: Do junctions support determining interesections of lists
2006/4/4, Luke Palmer [EMAIL PROTECTED]: I don't follow. Why is that the representation of any(1,2,3)? Is this a disjunctive normal form; i.e. is 2 any(1,2,3) equivalent to the test: 2 1 || 2 2 || 2 3 || 2 1 2 2 || ... 2 1 | 2 2 | 2 3 which ends up being the same thing after simplification - Flavio S. Glock
Re: Junctions again (was Re: binding arguments)
On 1/5/06, TSa [EMAIL PROTECTED] wrote: Jonathan Lang wrote: Therefore, $x = 3; if $x = 1 5 {say 'smaller'} if $x 1 5 {say 'larger'} should produce exactly the same output as $x = 3; if $x = 1 $x = 5 {say 'smaller'} This is slightly untrue. because if the junction contains two identical values or an undef ordered object the part is essentially stripped away: if $x = 5 $x = 5 {say 'smaller'} can be permuted into if $x = 5 5 $x {say 'smaller'} and optimized to if $x == 5 {say 'smaller'} Do you claim that if $x = 5 $x = 5 {say 'smaller'} is same as if $x == 5 {say 'smaller'} -- Markus Laire
Re: Junctions again (was Re: binding arguments)
Rob Kinyon wrote: To me, this implies that junctions don't have a complete definition. Either they're ordered or they're not. Either I can put them in a = expression and it makes sense or I can't. If it makes sense, then that implies that if $x = $y is true, then $x $y is false. Otherwise, the definitions of = and have been violated. I'll beg to differ. If you insist on that kind of restriction on Junctions, they won't be able to serve their original (and primary) purpose of aggragating comparison tests together. Remember: if $x = 1 5 {...} is intended to be 'shorthand' for if $x = 1 $x = 5 {...} Therefore, $x = 3; if $x = 1 5 {say 'smaller'} if $x 1 5 {say 'larger'} should produce exactly the same output as $x = 3; if $x = 1 $x = 5 {say 'smaller'} if $x 1 $x 5 {say 'larger'} If it doesn't, then Junctions are useless and should be stricken from Perl 6. And the definition of '' is greater than, not not (less than or equal to). The latter is a fact derived from how numbers and letters behave, not anything inherent in the comparison operator. Just like '=' is less than or equal to, as opposed to not greater than. You aren't violating the definitions of = and by failing to insist that they be logical negations of each other; you're only violating the common wisdom. -- Jonathan Dataweaver Lang
Re: Junctions again (was Re: binding arguments)
On 1/4/06, Luke Palmer wrote: The other thing that is deeply disturbing to me, but apparently not to many other people, is that I could have a working, well-typed program with explicit annotations. I don't think it disturbs me... but that might just be because I don't really understand it. I could remove those annotations and the program would stop working! If it changes how the program works, then by definition doesn't that mean it wasn't really an annotation to begin with? As far as specifying Junction in signatures to control auto-threading, that always felt funny to me anyway, because it's not consistent with the normal meaning of specifying a parameter type. I would've expected is threaded or is junctive or is junctothreaded or something. I'm not sure if this is (part of) what you're getting at or not. In a strongly-typed language, can you always remove the typing from a working program without changing it? Or maybe just particular strongly-typed languages... in Perl, typing can be used to provide bonus information (say, as optimisation hints); but it can also be used for multiple-dispatch, so I certainly wouldn't expect a program to continue working properly if I changed *that* information. (Assuming well-typed refers to the former, but not the latter -- hope I've got that straight.) In that vein, I think of junctions as a sort of implicit polymorphism: I define sub foo(Int $a) and also get sub foo(Junction of Ints $j) for free. Which is why acting wacky doesn't bother me -- numbers may be well-ordered, but junctions aren't, and there are two different 's at work. Arguably, different functions should have different names to avoid confusion, but I think that calling the junctive less-than something other than would be even more confusing. (Certainly it would be too unDWIMilly pedantic to be Perl.) Of course, I was also never bothered by using + to mean numeric addition and string concatenation. Come to think of it, perhaps that's because languages which do that are picky about distinguishing strings from numbers -- in Basic, 123 + 123 will get you a type-mismatch error, but to Perl, 123 and 123 are the same thing, so you need a numeric == and a stringic 'eq'. But Perl does know the difference between a number and a junction. That means the programmer has to follow along at home, but ok, sometimes you just gotta be aware of what your code is doing. I think I understand your Functor proposal, and it does have a certain appeal for me... but along with the advantage of making it clearer when junctions are being used, it carries the disadvantage of *requiring* you to know when junctions are being used. I can't just say if $x3 ... and expect it to Do the Right Thing regardless of whether $x happens to be an ordinary number or a junction -- I have to split up the two cases and handle them separately. That's surely going to reduce the happy-go-lucky usefulness of junctions. Besides, don't we have a no junctions pragma that you can stick into any scope where you need exact mathematical purity? -David
Re: Junctions again (was Re: binding arguments)
HaloO, Jonathan Lang wrote: Rob Kinyon wrote: To me, this implies that junctions don't have a complete definition. Either they're ordered or they're not. So, is there a number between 0 and 1? Shades between black and white? When is a 360 degree turn not returning a system into its initial state? What has a 720 degree turn to do with sign reversal, negation and twisted arms? Anyone know the Eisenstein integers? Is 5 a prime complex number? What is its quadratic residue? (-1)**2 == -i**2 == +1 \ ?--0 # if = / i**2 == -1 -- mirror symmetry axis j**2 == -1 \ !--0 # unless = / (-1)**2 == -j**2 == +1 But note that *same* symmetrie is broken! Ever wondered why a mirror changes left and right, but not up and down? And what has all that to do with anagrams like 'OTTO' and 'TOOT' or with bits '.**.' and '*..*'? Or the range operators ^..^ .^^.? Conceptually the 0 has no sign unless you want it to be junctive ;) if you rotate the above vector diagrams by 120 degrees endlessly clockwise and counter clockwise you get upper: ...,0, 1,-1,0,... lower: ...,0,-1, 1,0,... which when superimposed additively lets the infinity of the lists nicely vanish. But not the same is not true if one is shifted, the other squared and then subtracted, or some such. The thing is you end up with the infinte list (...,!0,!0,...). The net effect is the same as reading the list's string representations in opposite directions. There is no dark side of the moon really! Here's the same in another ascii picture: i\+/+ -\+ +\-2**-=+**2+/+ -/- -/-\-i**2 center stage we find = which returns one(-1,0,+1) or rotations thereof: one(0,+1,-1) or one(+1,-1,0). Or the odd permutations one(0,-1,+1), one(-1,+1,0) and one(+1,0,-1). In other words three pairs of ones that cancel each other if zipped additively. The only thing we need is a neutral element to get a group. Let's take the empty one() junction. But an empty any() would do as well. These sort of represent no comparison at all and a comparison you don't care to constrain any further! In the latter case an undef return value is not unexpected, I hope. This is how that looks in an example: 'foo' cmp 'bor' -- f o o »cmp« b o r -- -- (-1, +0, +1) | (+1, -0, -1) -- The arrows indicate reading direction of the respective string. In a optimised implementation the outer f/b and and r/o give the invariant relative positions of one('foo','oof') and one('bor','rob') in the order of strings in viewing direction. At least that is the observable behaviour. Endianess of the machine, representation of junctions and what not may differ for concrete implementations of Perl6 :) Note that [?] (-1, +0, +1) »+« (+1, -0, -1) -- [?] (0,0,0) -- false With (-++) and (+--) beeing dual Minkowski metrics. Either I can put them in a = expression and it makes sense or I can't. HiHi, this is a statement about the programmer's abilities... not about Perl 6 the language! If it makes sense, then that implies that if $x = $y is true, then $x $y is false. Otherwise, the definitions of = and have been violated. I'll beg to differ. If you insist on that kind of restriction on Junctions, they won't be able to serve their original (and primary) purpose of aggragating comparison tests together. Remember: if $x = 1 5 {...} is intended to be 'shorthand' for if $x = 1 $x = 5 {...} I beg to differ, two err too. I mean potentially from both depending on what they intented to say and how I understood them. My point is that the junctive case sort of means: if $x.all:{=}(1,5) {...} where :{=} receives similar meta treatment as [=] reduce would. BTW, isn't bareword suffixing {=} reserved for type theoretic manipulations? I still regard the junctions as Code subtypes and thus any{=} and friends as parametric meta operation. Therefore, $x = 3; if $x = 1 5 {say 'smaller'} if $x 1 5 {say 'larger'} should produce exactly the same output as $x = 3; if $x = 1 $x = 5 {say 'smaller'} This is slightly untrue. because if the junction contains two identical values or an undef ordered object the part is essentially stripped away: if $x = 5 $x = 5 {say 'smaller'} can be permuted into if $x = 5 5 $x {say 'smaller'} and optimized to if $x == 5 {say 'smaller'} if $x 1 $x 5 {say 'larger'} If it doesn't, then Junctions are useless and should be stricken from Perl 6. And the definition of '' is greater than, not not (less than or equal to). The latter is a fact derived from how numbers and letters behave, not anything inherent in the comparison operator. The complete group of comparison operators imposes the order on the underlying uninterpreted set
Re: Junctions again (was Re: binding arguments)
Me no follow. Please use smaller words? -- Jonathan Dataweaver Lang
Re: Junctions again (was Re: binding arguments)
HaloO, Luke Palmer wrote: Junctions are frightfully more abstract than that. They only take on meaning when you evaluate them in boolean context. Before that, they represent only a potential to become a boolean test. This is very well spoken err written---except that I would use beautifully there :) Well, and their meaning is sort of reduced to one(0,1) in boolean context. It does not originate there ;) So junctions are mean outside boolean context :)) BTW, is 'the means' just the plural of 'the mean' or are these two completely unrelated substantives? E.g. does one say 'a means' with 'means' beeing a singular noun? How about the type Mean or Means as supertype of the four junction types? For example contrasting them with Plain values? So, to support the four junction generators the compiler has to decide at a boolean node of the AST if the subtree originating there could possibly be junctive and prepare the code for it! If there is no proof or disproof, this decision must be deferred to runtime when the actual data---that is the involved parties not their types---are available. OTOH, the programmer might short-cut very easily with a 'no junctions' in the scope. BTW, does that imply that junctions fall back to list behaviour when it comes to evaluating the node? How does this lexical pragma traverse the dynamic scopes at runtime? In other words how do junctive and non-junctive parts of a program interact? Once again this boosts my believe that junctions should travel in code vars. E.g. my test = any(1,2,3).assuming:op==; my $x = 3; if $x.test {???} Also the typeish aspects of first class closures is somewhat under-represented in Perl6---or I don't see it. What should e.g. the following my $sci := (sin == cos); # intersectons of sin and cos put into the var? I think it is a lazy list(ref), an iterator or generator or simply a calculated code object(ref) with type :(Ref of List of Num where {sin == cos}). In other words @sci = pi/4 »+« pi »*« (-Inf..+Inf); # :(Array of List ...) where I would like the last thing beeing written (-Inf,,+Inf) or (-Inf,,,). Actually it is the Int type as list, set or any. With real ranges it might be (-Inf..+Inf):by(pi) or so. To summarize: I propose to unify the invocations of junctions with embedded closure calls in general. Of these Perl6 has got many: there are pipes, lazy lists, slices, control structures, sorting, key extraction, ... --
Re: Junctions again (was Re: binding arguments)
On 1/2/06, TSa [EMAIL PROTECTED] wrote: HaloO, Luke Palmer wrote: The point was that you should know when you're passing a named argument, always. Objects that behave specially when passed to a function prevent the ability to abstract uniformly using functions.[1] ... [1] This is one of my quibbles with junctions, too. You mean the fact that after $junc = any(1,2,3) there is no syntactical indication of non-scalar magic in subsequent uses of $junc e.g. when subs are auto-threaded? I strongly agree. But I'm striving for a definition where the predicate nature of the junctions is obvious and the magic under control of the type system. I'm confused at the confusion. To me, junctions are just magical values, not magical scalars. In theory, one should be able to create junctions of arrays, hashes, or subs just as easily. my @junc = any( @a, @b, @c ); my %junc = any( %a, %b, %c ); Then, if @junc[2] == 9 { ... } would imply if @a[2] == 9 || @b[2] == 9 || @c[2] == 9 { ... } IMHO, one thing that may be causing issues with the junction concept is that I've never seen anyone talk about the implicit read-only behavior of a junction. To me, a junction would be required to be read-only (except for overall assignment). To modify the junction would be to overwrite it. So, given my $junc = any( $a, $b, $c ); If you wanted to add $d into there, you'd have to do it this way: $junc = any( $junc, $d ); Obviously, modifications to $a, $b, or $c would carry through. Doing this means that array, hash, and sub junctions make sense and behave no differently than any other readonly variable. In fact, this behavior seems mandated given the possibility of tying variables (or is this a Perl5ism that is being discarded in Perl6?) Rob
Re: Junctions again (was Re: binding arguments)
On 1/4/06, Rob Kinyon [EMAIL PROTECTED] wrote: Luke Palmer wrote: The point was that you should know when you're passing a named argument, always. Objects that behave specially when passed to a function prevent the ability to abstract uniformly using functions.[1] ... [1] This is one of my quibbles with junctions, too. I'm confused at the confusion. To me, junctions are just magical values, not magical scalars. In theory, one should be able to create junctions of arrays, hashes, or subs just as easily. This really has nothing to do with what I was talking about. Here's what I was talking about: my $j = get_junction(); # asks for a junction from the user if $j.values 4 { die Too many values } my $k = get_junction(); if $k.values 4 { die Too many values } my $l = get_junction(); if $l.values 4 { die Too many values } You'd like to abstract this to: sub toomany($j) { if $j.values 4 { die Too many values } return $j; } my ($j,$k,$l) = map { toomany(get_junction()) } ^3; But junctions are so special, that this abstraction wouldn't work. Yes, yes, you say oh, just put a 'Junction' type on the $j parameter. That's not the point. The point is that now I have to be aware whenever I'm using a junction, and I have to declare all my generics as being able to take junctions, instead of it just being obvious that they do because I didn't put any constraints on the values. I figure that if you don't have any constraints on the values, you're not assuming anything about them, so using a junction should be fine. Of course, this was introduced for a reason: sub min($x,$y) { $x = $y ?? $x !! $y } sub min2($x, $y) { if $x = $y { return $x } if $x $y { return $y } } In the presence of junctions, these two functions are not equivalent. In fact, it is possible that both or neither of the conditionals succeed in min2(), meaning you could change the order of the if statements and it would change the behavior. This is wacky stuff, so we said that you have to be aware that you're using a junction for safety. But now I'm convinced, but I've failed to convince anyone else, that the behavior's being wacky doesn't mean that it should be declared, but that the behavior is just plain wrong. I figure that if something says it's totally ordered (which junctions do simply by being allowed arguments to the = function), both of these functions should always be the same. The fact is that junctions are not totally ordered, and they shouldn't pretend that they are. The other thing that is deeply disturbing to me, but apparently not to many other people, is that I could have a working, well-typed program with explicit annotations. I could remove those annotations and the program would stop working! In the literature, the fact that a program is well-typed has nothing to do with the annotations in the program; they're there for redundancy, so they can catch you more easily when you write a poorly-typed program. But in order to use junctions, using and not using annotations can both produce well-typed programs, *and those programs will be different*. So that's what I was talking about. It didn't have anything to do with the read-onlyness of junctions. Luke
Re: Junctions again (was Re: binding arguments)
HaloO, Rob Kinyon wrote: I'm confused at the confusion. To me, junctions are just magical values, not magical scalars. In theory, one should be able to create junctions of arrays, hashes, or subs just as easily. my @junc = any( @a, @b, @c ); my %junc = any( %a, %b, %c ); Hmm, and this is unflattened my @joj = any( @a; @b; @c ); and [EMAIL PROTECTED] -- any( [EMAIL PROTECTED]; [EMAIL PROTECTED]; [EMAIL PROTECTED] ); then? How long is the junctiveness kept? Then, if @junc[2] == 9 { ... } would imply if @a[2] == 9 || @b[2] == 9 || @c[2] == 9 { ... } Uhh, and if @joj[2] == 9 { ... } should effectively means if @joj[2;*] == 9 { ... } with re-junctification of the sliced out arrays? if any( [;] @joj.values[2;*] ) == 9 { ... } IMHO, one thing that may be causing issues with the junction concept is that I've never seen anyone talk about the implicit read-only behavior of a junction. To me, a junction would be required to be read-only (except for overall assignment). To modify the junction would be to overwrite it. So, given my $junc = any( $a, $b, $c ); Like Ref values, then? If you wanted to add $d into there, you'd have to do it this way: $junc = any( $junc, $d ); Obviously, modifications to $a, $b, or $c would carry through. Which first of all smells strongly like closure creation, that is Code types! But shouldn't the read-only enreferencing be more prominent notationally? Like my $junc = any( \$a, \$b, \$c ); or through an Arglist (which means malice in German): my $junc = any\( $a, $b, $c ); Otherwise I would strongly opt for value snapshotting when the junction closure is created. And of course the underlying functionality must be easily available for user defined junctions. Things like set-, min-, max- and sort-junctions come to mind... Doing this means that array, hash, and sub junctions make sense and behave no differently than any other readonly variable. Combined with lazy evaluation that yields on unavailable values we enter the realm of constraint programming. The grand unification then comes with multi threading this concurrently. With side-effects that becomes *REALLY* challenging! In fact, this behavior seems mandated given the possibility of tying variables (or is this a Perl5ism that is being discarded in Perl6?) That is what := does these days? BTW, a rw junction is just three chars around the corner: my $junc = any:rw( $a = 1, $b = 2, $c = 4);#1 my $junc = any( $a = 1, $b = 2, $c = 4, :rw); #2 my $junc = any( $a = 1, $b = 2, $c = 4 ):rw; #3 $junc = 3; # means $junc.pick = 3? I'm not sure which syntax of #1 to #3 really hits the junctions creator with a named arg. And it might not support it for good reasons! Just think what fun breaks loose if someone hands around an array that contains (rw = 1): push @array, (rw = 1); $surprise = any([EMAIL PROTECTED]); Or simply my $junc := any( $a = 1, $b = 2, $c = 4); So, do we want junctive assignment? Or should it complain like my $val := 3; # error: can't bind constant hopefully does. --
Re: Junctions again (was Re: binding arguments)
HaloO, Luke Palmer wrote: Which reads nicely, but it is quite opaque to the naive user. I guess many things are opaque to naive users ;) Whatever solution we end up with for Junctions, Larry wants it to support this: if $x == 1 | 2 | 3 {...} And I'm almost sure that I agree with him. This actually would be easy if Larry decided that *all* operators are recognized syntactically and dispatched at runtime. But he likes to have == strictly mean numeric comparison. Well, with the twist that the numericy is imposed on the values retrieved from the list backing the any-junction and the whole thing beeing settled at compile time syntactically. But if we assume that all information that is available to the compiler is available to the runtime as well, then I don't see any reason why the evaluation of the condition above might not be a dispatch on the if flow controller multi sub or some such with some JITing and auto-loading thrown in. Let me illustrate the point with the well know set of the two inner operators of nums + and * where * is sort of defined in terms of +: 3 * 4 -- 12 # symmetric MMD, infix notation, # atomic evaluation (3 *)4 -- 4+4+4 # asymmetric prefix, left adjoined operator, # two step evaluation (addition used for illustration) # 1: curry lhs to form prefix op # 2: apply op from step 1 3(* 4) -- 3+3+3+3 # asymmetric postfix, right adjoined operator, # two step evaluation I think the compiler decides which of the alternatives is applicable and generates code accordingly. But why shouldn't it defer the generation of the semantic tree until dispatch time where the associativity of the op and the involved types are known? I would call that syntax tree dispatch or perhaps multi stage MMD. With caching the results in a local multi this appears as doable to me. There is a conflict of design interest here. We would like to maintain: * Function abstraction * Variable abstraction With container types these two are embedded into the type system which I still hope supports arrow types properly. I've sort of developed the mental model of -- being a co-variant forward flow of control or program execution and -- beeing a contra-variant keeping of achieved state: -- sub junction / iteration / implication / flow -- resub junction / reiteration / replication / keep -- bisub junction / equivalence / rw container / sync / snap (shot) The latter two are not yet Perl 6, and the -- has a contra-variant part in the non-invocant params, which are of course sync or snap points of a program. Note that lazy params aren't snapped valueish but typeish in the sense that the imposed constraints *at that moment* in execution time hold. Well, and if they don't then we have of course 'ex falso quod libet' later on :) There's got to be a good solution lying around here somewhere... Hmm, operator junctions perhaps? I think that the three relations , == and are the prototypical order ops. I do not see a priori numerics in them. This is at best Perl 5 legacy. Note that =, != and = are two element any-junctions from the set of the three primary comparators. And = is a one-junction of all three with succeeding mapping of the ops to -1, 0 and +1. Together with negation as center point we get the Fano Plane of the comparison ops in a crude ASCII chart: -1|0 00|+1 {=}---{==}---{=} \/ \ {! } / {} {} none(0,1) -- -1 \ / +1 -- none(-1,0) \/ {!=} -1|+1 -- none(0) = -- one(-1,0,+1) as circle connecting {} {==} {} can theory theory capture these things in a systematic framework? --
Re: Junctions again (was Re: binding arguments)
Luke Palmer wrote: Whatever solution we end up with for Junctions, Larry wants it to support this: if $x == 1 | 2 | 3 {...} And I'm almost sure that I agree with him. It's too bad, because except for that little detail, fmap was looking pretty darn nice for junctions. Not really. If I read the fmap proposal correctly, if any($x, $y, $z) »==« any(1, 2, 3) {...} would do the same thing as if $x == 1 || $y == 2 || $z == 3 {...} ...which fails to dwim. Not to mention if all($x, $y, $z) »==« any(1, 2, 3) {...} if any($x, $y, $z) »~~« all($a, $b, $c) {...} ...which ought to work like if ($x == 1 || $x == 2 || $x == 3) ($y == 1 || $y == 2 || $y == 3) ($z == 1 || $z == 2 || $z == 3) {...} if ($x ~~ $a $x ~~ $b $x ~~ $c) || ($y ~~ $a $y ~~ $b $y ~~ $c) || ($z ~~ $a $z ~~ $b $z ~~ $c) {...} And then there's the (minor) ugliness of having to remember to include hyperspanners (» and/or «) whenever you want to evaluate junctions. -- Side note: any(1, 2, 3) is indistinguishable from one(1, 2, 3), because the values 1, 2, and 3 are mutually exclusive. People often use the inclusive disjunction when they mean the exclusive one, and get away with it only because the values that they're dealing with are mutually exclusive. Another issue is that one-junctions conceptually represent a single value at a time - though which one is unknowable - whereas any-junctions can also represent several values at once, all-junctions usually do so, and none-junctions can even represent no values. Conceptually, one-junctions are scalar-like, while the other kinds of junctions are list-like; so one ought to think of $a ~~ one(@set) as matching a scalar to a scalar, whereas $a ~~ any(@set) would be matching a scalar to a list (and thus would more properly be $a ~~« any(@set)). But because the distinction between inclusive and exclusive disjunctions is moot when the component choices are already mutually exclusive, there's an advantage to any-junctions and one-junctions behaving in the same way. -- Jonathan Dataweaver Lang
Re: Junctions again (was Re: binding arguments)
On 1/4/06, Jonathan Lang [EMAIL PROTECTED] wrote: And I'm almost sure that I agree with him. It's too bad, because except for that little detail, fmap was looking pretty darn nice for junctions. Not really. If I read the fmap proposal correctly, You didn't :-) if any($x, $y, $z) »==« any(1, 2, 3) {...} would do the same thing as if $x == 1 || $y == 2 || $z == 3 {...} The key point is that == just threads == through the (binary in this case) functor, and it's up to the functor to decide what that means. For lists: (1,2) + (3,4) === (4,6) But for junctions: 1|2 + 3|4 === 4|5|5|6 === 4|5|6 The thing that makes lists zip-thread is the definition the Functor{List} instance, not anything fundamental about functors. Side note: any(1, 2, 3) is indistinguishable from one(1, 2, 3), because the values 1, 2, and 3 are mutually exclusive. That's only true when you're thinking about equality: 1 any(1,2,3) # true 1 one(1,2,3) # false (1 2 and 1 3) People often use the inclusive disjunction when they mean the exclusive one, and get away with it only because the values that they're dealing with are mutually exclusive. Another issue is that one-junctions conceptually represent a single value at a time - though which one is unknowable - Junctions are frightfully more abstract than that. They only take on meaning when you evaluate them in boolean context. Before that, they represent only a potential to become a boolean test. You could think of them like an operator voltage: a comparison divided by the operator and one of the operands. Luke
Junctions again (was Re: binding arguments)
HaloO, Luke Palmer wrote: The point was that you should know when you're passing a named argument, always. Objects that behave specially when passed to a function prevent the ability to abstract uniformly using functions.[1] ... [1] This is one of my quibbles with junctions, too. You mean the fact that after $junc = any(1,2,3) there is no syntactical indication of non-scalar magic in subsequent uses of $junc e.g. when subs are auto-threaded? I strongly agree. But I'm striving for a definition where the predicate nature of the junctions is obvious and the magic under control of the type system. The least I think should be done here is to restrict the magic to happen from within vars combined with not too much auto-enref and -deref of junction (code) refs. The design is somewhat too friendly to the junctions are values idea but then not auto-hypering list operations... But I have no idea for this nice syntax, yet. Perhaps something like my junc = any(1,2,3); my $val = 1; if junc( infix:==, $val ) {...} which is arguably clumsy. The part that needs smarting up is handing in the boolean operator ref. Might a slurpy block work? if junc($val): {==} {...} Or if junc:{==}($val) {...} Or $val out front if $val == :{junc} {...} which doesn't work with two junctions. Or reduce syntax: if [==] junc, $val {...} OTOH, explicit overloads of all ops applicable to junctions might end up where we are now: if $junc == $val {...} Hmm, wasn't that recently defined as actually beeing if +$junc === +$val {...} # 3 === 1 -- false Or how else does a junction numerify? Thus the problem only remains with generic equivalence if explicit, inhomogenous overloads for junctions exist. And there are no generic , , = and =. Does a !== or ^^^ antivalence op exist? I guess not. --
Re: Junctions again (was Re: binding arguments)
On 1/2/06, TSa [EMAIL PROTECTED] wrote: But I have no idea for this nice syntax, yet. Perhaps something like my junc = any(1,2,3); my $val = 1; if junc( infix:==, $val ) {...} which is arguably clumsy. I don't think anyone would waste his time arguing that. :-) The part that needs smarting up is handing in the boolean operator ref. Might a slurpy block work? if junc($val): {==} {...} This all reminds me of Haskell's incantation of the same thing: if (x ==) `any` [1,2,3] then ... else ... Which reads nicely, but it is quite opaque to the naive user. Whatever solution we end up with for Junctions, Larry wants it to support this: if $x == 1 | 2 | 3 {...} And I'm almost sure that I agree with him. It's too bad, because except for that little detail, fmap was looking pretty darn nice for junctions. There is a conflict of design interest here. We would like to maintain: * Function abstraction * Variable abstraction for junctions, but we would also like to maintain genericity with respect to user-defined operators. Of the proposals so far: Quantum::Superpositions behavior violates genericity with respect to user-defined operators. Autothreading behavior violates function abstraction. Lexical expansion (i.e. just having the compiler turn $x == 1 | 2 into $x == 1 || $x == 2) violates variable abstraction. So, with these three constraints in mind, fmap again comes out on top. Yes, I'm quite proud of it. Unfortuately, it's ugly, and that's a constraint too. There's got to be a good solution lying around here somewhere... Luke
Re: Junctions, patterns, and fmap again
On 20/09/05, Luke Palmer [EMAIL PROTECTED] wrote: The basic idea is that, alongside Functor, you have a Zippable theory which defines: theory Zippable[::T] { multi zip (T[::A], T[::B] -- T[:(::A, ::B)]) {...} } Where that last coloney madness is a yet-to-be-proposed tuple type (but tuples can be emulated if they are not in the core language, so it's no biggie). That is, zip takes two structures and figures out how to combine them in a reasonable way into pairs of values. So: zip([1,2,[3,4]], [[a,b], c, d]) Gives: [[:(1,a), :(1,b)], :(2,c), [:(3,d), :(4,d)]] Oh, looks like I was way off. So in this particular scenario, when one side 'runs out' of structure, that part degenerates to a one-side fmap using the leaf value as the non-hyper arg. Of course, this is the behaviour for /built-in/ arrays--it's up to the person defining fzip to determine how to handle their own Zippable types. So, if they want fzip to fail() on incompatible structures, or do some other crazy thing, they can just put that in their version of fzip. So it's really up to the zippable functor itself to figure out the best way to zip. After the structures are zipped up, you fmap the binary function on each of the tuples, resulting in a reasonable functor structure again. Bottom line: user-defined fzip turns two structures into one structure of pairs (in whatever way the user deems reasonable), and then fmap transforms the tuples of that one structure. For things like `foo(»$x«, »$y«, »$z«)` (assuming it ends up being supported), you would either extend fzip over n-tuples, or just use pair-fzip repeatedly and reduce the nested pairs into a single n-tuple. Nope. Here it is. And it was 22 lines. :-) http://svn.luqui.org/svn/misc/luke/work/code/haskell/hyper.hs Thanks, that made it a lot clearer. Haskell++ :) I just hope you and I aren't the only ones who think this is a great idea... Stuart
Re: Junctions, patterns, and fmap again
On 19/09/05, Luke Palmer [EMAIL PROTECTED] wrote: Part 1: fmap I have a plan for the $x »+« $y form (and also foo(»$x«, »$y«, »$z«)), but I don't want to go into that right now. It basically involves zipping the structures up into tuples and applying the function to the tuples. Does this mean that 'unary' (one-side) hyper would be structure-preserving, but 'binary' (two-side) hyper would not? Or would you take the final list of tuples and re-build a structure? I guess it comes down to whether you want to allow binary-hyper on values that aren't structurally equivalent. Either you flatten both structures to lists (which might be semantically dubious), or you disallow binary-hyper on structurally distinct arguments (which might prohibit some useful operations). Or you do something inconsistent. (Have you written any of these deep details up somewhere? I'd love to read them.) Part 2: Junctions So my proposal is to make a Junction into a plain old Functor. So what used to be: if any(@values) == 4 {...} Is now: if any(@values) »== 4 {...} And the only thing that makes junctions different from Sets (which are also Functors) is their behavior in boolean context (and their ability to be Patterns; see below). I think this is really nice: we get rid of invisible junction magic, yet accessing that magic explicitly is only one or two characters away. Being able to pass junctions around as values (safely) is a nice bonus too. Stuart
Re: Junctions, patterns, and fmap again
On 9/19/05, Stuart Cook [EMAIL PROTECTED] wrote: On 19/09/05, Luke Palmer [EMAIL PROTECTED] wrote: Part 1: fmap I have a plan for the $x »+« $y form (and also foo(»$x«, »$y«, »$z«)), but I don't want to go into that right now. It basically involves zipping the structures up into tuples and applying the function to the tuples. Does this mean that 'unary' (one-side) hyper would be structure-preserving, but 'binary' (two-side) hyper would not? Or would you take the final list of tuples and re-build a structure? Well, I've written up the details in a 40 line Haskell program to make sure it worked. I think I deleted the program, though. The basic idea is that, alongside Functor, you have a Zippable theory which defines: theory Zippable[::T] { multi zip (T[::A], T[::B] -- T[:(::A, ::B)]) {...} } Where that last coloney madness is a yet-to-be-proposed tuple type (but tuples can be emulated if they are not in the core language, so it's no biggie). That is, zip takes two structures and figures out how to combine them in a reasonable way into pairs of values. So: zip([1,2,[3,4]], [[a,b], c, d]) Gives: [[:(1,a), :(1,b)], :(2,c), [:(3,d), :(4,d)]] In order to be consistent with the specced semantics. In order to keep with the specced semantics of junctions, you'll probably see: zip(1|2, 34) Give: (:(1,3) :(1,4)) | (:(2,3) :(2,4)) So it's really up to the zippable functor itself to figure out the best way to zip. After the structures are zipped up, you fmap the binary function on each of the tuples, resulting in a reasonable functor structure again. Hmmm, that should probably be fzip or something. Luke
Re: Junctions, patterns, and fmap again
On 9/19/05, Luke Palmer [EMAIL PROTECTED] wrote Well, I've written up the details in a 40 line Haskell program to make sure it worked. I think I deleted the program, though. Nope. Here it is. And it was 22 lines. :-) http://svn.luqui.org/svn/misc/luke/work/code/haskell/hyper.hs Luke
Junctions, patterns, and fmap again
Okay, due to some discussion on #perl6, I'll assume that the reason my fmap proposal was Warnocked is because a fair number of people didn't understand it. Also, for the people who did understand, this message includes a complete proposal for the workings of Junctions that will fluster Damian again. :-) Part 1: fmap De-symmetricalize hyper. So, what used to be @foo »+« 1 is now @foo »+ 1; the hyper marker is only on the side of the operator that is being hypered over. Of course, we still have @foo »+« @bar. An object may do the role[1] Functor, in which case it defines a method 'fmap' which is a generalization of map. For instance, let's try it with a tree. class Tree does Functor { method fmap (code) {...} } class Branch is Tree { has Tree $.left; has Tree $.right; method fmap (code) { # Return an identical tree with the leaves mapped with code return Branch.new( left = $.left.fmap(code), right = $.right.fmap(code), ); } } class Leaf is Tree { has $.data; method fmap (code) { # Just apply code to the value in the leaf return Leaf.new( data = code($.data) ) } } Now if we have a $tree that looks like: +---+---3 | +---4 +---5 $tree.fmap:{ $_ * 2 } returns: +---+---6 | +---8 +---10 The formal signature of fmap is, if T is a Functor: multi fmap (T[::U], code:(::U -- ::V) -- T[::V]) That is, it takes a T of some type, and a code that maps some type to some other type, and returns a T of that other type. Now, hypers are just syntactic sugar for various forms of fmap: $x »+ $y# $x.fmap:{ $_ + $y } $x +« $y# $y.fmap:{ $x + $_ } foo(»$x«) # $x.fmap:{ foo($_) } I have a plan for the $x »+« $y form (and also foo(»$x«, »$y«, »$z«)), but I don't want to go into that right now. It basically involves zipping the structures up into tuples and applying the function to the tuples. Part 2: Junctions A Junction is a set of values together with a logical operation to be applied when the Junction is in boolean context. When you add to a Junction, you add to each of its values. When you pass a Junction to a function, you call the function for each of its values and reconstruct based on the return values. All in all, a Junction sounds like a perfect candidate to be a Functor. Except all the fmapping is implicit, which is what makes Junctions break the transitivity of , the orthogonality of the patterns 1 and 2, and all that other stuff that people like me covet so. So my proposal is to make a Junction into a plain old Functor. So what used to be: if any(@values) == 4 {...} Is now: if any(@values) »== 4 {...} And the only thing that makes junctions different from Sets (which are also Functors) is their behavior in boolean context (and their ability to be Patterns; see below). Yeah, it's a little teeny bit longer, but I think it is pretty easy to get used to. And now junctinve threading looks like threading (just like with hypers). The best part is that now it is okay to pass Junctions to functions since they don't screw with your logical assumptions, and the signature (Junction $x) is no longer semantically special; it is a type check just like any other typed signature (and optional just like any other typed signature :-). Part 3: Patterns Like I've said before, a Pattern is a thing that can be on the right side of a ~~ operator. Most builtin things are Patterns: numbers, strings, regexes, lists (maybe), booleans, closures, classes, and junctions. Pattern is really a role[2] that requires a match(Any -- Bool). So then $x ~~ $y is equivalent to $y.match($x). Here is a table of standard Patterns: numbers, strings: eqv regexes: match (note this gives us /foo/.match($str) for free) lists: dunno booleans: boolean truth (ignores left side) closures: apply closure and test truth classes: .does junctions: see below A Junction of Patterns does Pattern under its logical operation. So $x ~~ any($y,$z) is equivalent to $x ~~ $y || $x ~~ $z. This is the only autothreading operation. And that is so you can say: given $value { when 1 | 2 | 3 {...} when /^foo/ | /^bar/ {...} } The signature of grep is: sub grep (Pattern $pat, [EMAIL PROTECTED]) {...} So then these all make sense: grep /foo/, @values; grep 1|2, @values; grep Node, @objects And the regular closure form of grep is only for straight boolean tests against the argument: grep { lc eq 'foo' } @strings; This really doesn't give us anything new. But in my opinion, it solidifies what we already have greatly, and makes it much easier to think about and work with (no more guessing :-). It also trivializes the smart match table in S04. Luke [1] Really
Re: Sets (was: Reductions, junctions, hashslices, and cribbage scoring)
On Thu, 26 May 2005, Patrick R. Michaud wrote: The continuing exchanges regarding junctions, and the ongoing tendency by newcomers to think of them and try to use them as sets, makes me feel that it might be worthwhile to define and publish a standard CSet class and operations sooner rather than later in Perl 6 development. This might reduce the tendency to confuse junctions I fully second that. You can search the archives for my own thoughts on the subject. Michele -- you'll see that it shouldn't be so. AND, the writting as usuall is fantastic incompetent. To illustrate, i quote: - Xah Lee trolling in clpmisc, perl bug File::Basename and Perl's nature
Re: Reductions, junctions, hashslices, and cribbage scoring
On Wed, 25 May 2005, Rob Kinyon wrote: (This post references the discussion at http://www.perlmonks.org/?node_id=458728, particularly dragonchild's response at the bottom.) For those who don't know, cribbage is a game where each player has access to 4 cards, plus a community card. Various card combinations score points. The one in question is when cards add up to 15. If you have a group of cards that add up to 15, you receive 2 points. This is for every group, so if you have a ten and 2 fives, you get 4 points. Two tens and two fives is 8 points. Face cards are worth 10 and aces are 1, for these purposes. I proposed the following: # Fifteens $score += 2 * all( 15 == [EMAIL PROTECTED] any( 0 .. 4 ) } ); * Is this syntax legal? I think so. * Does it do what I want it to do? Definitely not. It looks like you are thinking of junctions in terms of arrays, instead of scalar quantum superpositions. any( 0 .. 4 ) This returns a scalar junction of the five values (0,1,2,3,4). What you want is clearly all possible subsets of 0..4. You probably should write a coroutine to generate a lazy list of them. @hand{ $junction } returns a scalar junction of the five cards in the hand. Junctions auto-thread through operators, including postcircumfixes. [+] $junction returns $junction, since [+] $scalar == $scalar. The individual values auto-thread through. 15 == $junction This returns a junction of booleans. Knowing the possible values of @hand, all of them are false. all( $junction ) I'm not real good with nested junctions... 2 * $junction This returns another junction, with all elements doubled. (still zeros) You obviously want 2 * junction.elems, but I'm not sure if junctions support that method. $score += $junction Again this will make $score a junction of values. It will not add each of the junction values to $score. You probably want something like C $score += $junction.values but that is another indication that you should be using arrays instead of junctions. And I'm not sure about the object interface to junctions anyway. * Is there another way? Assuming you write the subset coroutine above, how about $score += ( subsets(0..4) == map { 2 * (15 == [+] @[EMAIL PROTECTED]) } == [+] ) ~ John Williams
Re: Reductions, junctions, hashslices, and cribbage scoring
Assuming you write the subset coroutine above, how about $score += ( subsets(0..4) == map { 2 * (15 == [+] @[EMAIL PROTECTED]) } == [+] ) Working on it last night and this morning, I ended up with the following, very similar rewrite. sub gen_idx_powerset (Int $size is copy) returns Array { my @c = ([]); for 0 .. $size-1 - $i { push @c, (map { [EMAIL PROTECTED], $i] }, @c); } return @c; } # Fifteens $score += 2 * grep { 15 == [+]( @[EMAIL PROTECTED].val ) }, gen_idx_powerset( [EMAIL PROTECTED] ); (Also available at http://www.perlmonks.org/?node_id=460666) (I had an error in my original posting. @hand is an AoH. My original should have hypered to .val like my second one does.) Question: Is it possible using hypers and the like to replace the gen_idx_powerset() sub with an inline expression? I'm not worried about maintainability - I wanna see what the new ops can do! Thanks, Rob
Sets (was: Reductions, junctions, hashslices, and cribbage scoring)
On Thu, May 26, 2005 at 11:03:15AM -0600, John Williams wrote: I proposed the following: # Fifteens $score += 2 * all( 15 == [EMAIL PROTECTED] any( 0 .. 4 ) } ); * Is this syntax legal? I think so. * Does it do what I want it to do? Definitely not. First, apologies in advance for what I'm about to write: I'm going to express some thoughts/ideas below and then pretty much leave it to others to decide what (if anything) should be done with it. The continuing exchanges regarding junctions, and the ongoing tendency by newcomers to think of them and try to use them as sets, makes me feel that it might be worthwhile to define and publish a standard CSet class and operations sooner rather than later in Perl 6 development. This might reduce the tendency to confuse junctions with sets, by providing something that is more clearly a set and that has operations more closely aligned with what one is expecting. From a marketing perspective, it could reduce the initial frustration I suspect many people feel when they discover that junctions don't do the set-type things they initially thought they would, by providing something that does. It becomes natural to ask if CSet should be part of the Perl 6 core; I think that's a distinction and distraction not worrying about at this point. Clearly many people are trying to treat junctions as sets, perhaps because there's no well-understood alternative for it. Writing an alternative, even on a provisional basis, might be really helpful to people. Returning to the apology -- I recognize this is a @we ought to do X post where $Pm ~~ none(@we), but given that there are a lot of people who seem to like the notion of sets in Perl 6, I'm suggestion that anyone who wanted to take a crack at drafting a proposal or implementation would likely get lots of helpful feedback, suggestions, and contributions from people who are looking to use them. Pm
Reductions, junctions, hashslices, and cribbage scoring
(This post references the discussion at http://www.perlmonks.org/?node_id=458728, particularly dragonchild's response at the bottom.) For those who don't know, cribbage is a game where each player has access to 4 cards, plus a community card. Various card combinations score points. The one in question is when cards add up to 15. If you have a group of cards that add up to 15, you receive 2 points. This is for every group, so if you have a ten and 2 fives, you get 4 points. Two tens and two fives is 8 points. Face cards are worth 10 and aces are 1, for these purposes. I proposed the following: # Fifteens $score += 2 * all( 15 == [EMAIL PROTECTED] any( 0 .. 4 ) } ); * Is this syntax legal? * Does it do what I want it to do? * Is there another way? Thanks, Rob
Re: junctions vs English negatives.
On 5/14/05, Damian Conway [EMAIL PROTECTED] wrote: Larry wrote: I don't think we can allow this situation to stand. Either we have to make != and !~ and ne transform themselves via not raising, or we have to disallow negative comparisons on junctions entirely. Opinions? Making them DWIM here would be a mistake, since the dwimmery would disappear if anyone refactored: if $note != $do | $re | $me {...} to the supposedly identical: if $note != $do || $note != $re || $note != $me {...} That would be a bad outcome...pedagogically as well as from a maintainability point-of-view. Hmm. I'll just that if != is implemented like this: multi sub infix:!= (Any|Junction $a, Any|Junction $b) { !($a == $b); } Then it Just Works. Luke
Re: junctions vs English negatives.
On 5/15/05, Luke Palmer [EMAIL PROTECTED] wrote: multi sub infix:!= (Any|Junction $a, Any|Junction $b) { !($a == $b); } Then it Just Works. Also, that's the right way to provide a working != for any object which defines ==. We all want that, right? Ashley Winters
Re: junctions vs English negatives.
Luke wrote: Hmm. I'll just [mention] that if != is implemented like this: multi sub infix:!= (Any|Junction $a, Any|Junction $b) { !($a == $b); } Then it Just Works. I'd be fine with the dwimmy version if that is the underlying rule, since then the behaviour isn't a special case, and it's easy to explain that the magic of the C!= is being applied before the magic of junctions. Damian
Re: junctions vs English negatives.
On Mon, May 16, 2005 at 10:37:13AM +1000, Damian Conway wrote: : Luke wrote: : : Hmm. I'll just [mention] that if != is implemented like this: : : multi sub infix:!= (Any|Junction $a, Any|Junction $b) { : !($a == $b); : } : : Then it Just Works. : : I'd be fine with the dwimmy version if that is the underlying rule, since : then the behaviour isn't a special case, and it's easy to explain that the : magic of the C!= is being applied before the magic of junctions. Heh, I knew if I waited long enough I'd see arguments for both sides. Okay, let's go with the not raising. Ain't lingristiks wunnerfle. Larry
junctions vs English negatives.
We have a bit of a problem with negative operators applied to junctions, as illustrated recently on PerlMonks. To wit, when a native English speaker writes if $a != 1 | 2 | 3 {...} they really mean one of: if not $a == 1 | 2 | 3 {...} if $a == none(1, 2, 3) {...} or, expressed in current understanding of negated ops: if $a != 1 2 3 {...} if $a != all(1, 2, 3) {...} They specifically do *not* mean if $a != any(1,2,3) {...} since that would always be true. I don't think we can allow this situation to stand. Either we have to make != and !~ and ne transform themselves via not raising, or we have to disallow negative comparisons on junctions entirely. Opinions? Larry
Re: junctions vs English negatives.
On Sat, May 14, 2005 at 09:31:29AM -0700, Larry Wall wrote: I don't think we can allow this situation to stand. Either we have to make != and !~ and ne transform themselves via not raising, or we have to disallow negative comparisons on junctions entirely. I'm of the opinion that disallowing negative comparison on junctions is the best way to go. If I were better at this forensics stuff, I'd have a cogent argument to backup my position, but as it is all I can think of right now is this: if we make != comparison illegal on junctions, perl can give the programmer a helpful message when they forget whereas the other way, they just get unexpected behavior if they forget that != does something different than usual. -Scott -- Jonathan Scott Duff [EMAIL PROTECTED]
Re: junctions vs English negatives.
Larry Wall wrote: We have a bit of a problem with negative operators applied to junctions, as illustrated recently on PerlMonks. To wit, when a native English speaker writes if $a != 1 | 2 | 3 {...} they really mean one of: if not $a == 1 | 2 | 3 {...} if $a == none(1, 2, 3) {...} or, expressed in current understanding of negated ops: if $a != 1 2 3 {...} if $a != all(1, 2, 3) {...} They specifically do *not* mean if $a != any(1,2,3) {...} since that would always be true. unless $a = none(1,2) I don't think we can allow this situation to stand. Either we have to make != and !~ and ne transform themselves via not raising, or we have to disallow negative comparisons on junctions entirely. Opinions? I go with option 2b: leave the syntax the way it is, but fire off a warning, not an error when someone does this. -- Rod Adams
Re: junctions vs English negatives.
Larry wrote: I don't think we can allow this situation to stand. Either we have to make != and !~ and ne transform themselves via not raising, or we have to disallow negative comparisons on junctions entirely. Opinions? Making them DWIM here would be a mistake, since the dwimmery would disappear if anyone refactored: if $note != $do | $re | $me {...} to the supposedly identical: if $note != $do || $note != $re || $note != $me {...} That would be a bad outcome...pedagogically as well as from a maintainability point-of-view. I'd say we have to disallow negative comparisons against explicit (compile-time) junctions. That is, against expressions that explicitly use |//^ or any/all/one/none. Negative comparisons against implicit (run-time) junctions: if $note != $bad_note {...} still have to be allowed. Damian
Re: Junctions of classes, roles, etc.
Abhijit Mahabal wrote: When you dispatch, what happens would depend upon WALKMETH (according to the pseudocode for CALLONE in A12). Usually the first inherited method would get called. Ohh, yes, that thing. I forget about it. And actually I hope that there's a version among the standard pragmas that gives an error. Or actually this option should go to the typechecker and then the WALKMETH would nicely find a single, most specific method to call :) But the important thing for me in this thread is that there are no junctive bark methods in the alien beast classes! Well, unless the WALKMETH of choice implements them =:) -- TSa (Thomas Sandlaß)
Re: Junctions of classes, roles, etc.
David Storrs wrote: Let's move this away from simple types like Str and Int for a moment. If you consider them simple... Tell me what this does: class Tree { method bark() { die Cannot instantiate a Tree--it is abstract! } } class Birch { method bark() { return White, papery } } class Oak { method bark() { return Dark, heavy } } class Dog { method bark() { print Woof, woof!; return bow wow } } Four 'pure' classes so far. class AlienBeastie isa Tree isa Dog {} Here you get an error/warning of a composition time conflict between Tree::bark and Dog::bark. BTW, it's 'is' not 'isa'. My preferred syntax for multiple inheritance is the junctive notation 'is Tree Dog' for subclassing because it nicely allows for superclassing with 'is Tree | Dog'. class WhiteAlienBeastie isa Birch isa Dog {} Same for Birch::bark and Dog::bark. class HeavyAlienBeastie isa Oak isa Dog {} Same. sub Foo(Tree|Dog $x) { $x.bark() } This might dispatch correctly for 'pure' Trees, Dogs etc. but not for your mixed classes above. Regards, -- TSa (Thomas Sandlaß)
Re: Junctions of classes, roles, etc.
On Mon, 2 May 2005, [ISO-8859-1] Thomas Sandlaß wrote: David Storrs wrote: Tell me what this does: class Tree { method bark() { die Cannot instantiate a Tree--it is abstract! } } class Birch { method bark() { return White, papery } } class Oak { method bark() { return Dark, heavy } } class Dog { method bark() { print Woof, woof!; return bow wow } } Four 'pure' classes so far. class AlienBeastie isa Tree isa Dog {} Here you get an error/warning of a composition time conflict between Tree::bark and Dog::bark. I don't think so; I had come to the same conclusion before realising that we are talking inheritance here, not roles. So no trouble at class composition time. Superclasses do not enter the picture while composing. You'd be right if s/isa/is/ and then s/is/does/, of course. When you dispatch, what happens would depend upon WALKMETH (according to the pseudocode for CALLONE in A12). Usually the first inherited method would get called. TSa (Thomas Sandlaß) regards, abhijit
Re: Junctions of classes, roles, etc.
On Mon, May 02, 2005 at 06:49:10PM +0200, Thomas Sandlaß wrote: David Storrs wrote: Let's move this away from simple types like Str and Int for a moment. If you consider them simple... When compared to arbitrary-class-that-was-defined-by- arbitrary-programmer-of- arbitrary-and-unknown-skill-level then yes, I consider them to be extremely simple. Tell me what this does: class Tree { method bark() { die Cannot instantiate a Tree--it is abstract! } } class Birch { method bark() { return White, papery } } class Oak { method bark() { return Dark, heavy } } class Dog { method bark() { print Woof, woof!; return bow wow } } Four 'pure' classes so far. Dog is not pure according to the definition of pure class that I know (no side effects in any method, constructor, or subclass). Maybe 'pure class' means something else to you? class AlienBeastie isa Tree isa Dog {} Here you get an error/warning of a composition time conflict between Tree::bark and Dog::bark. So that I'm clear, is this your opinion/preference or is it based on material from the SEAs? If the latter, could you point me to the relevant passage? My preferred syntax for multiple inheritance is the junctive notation 'is Tree Dog' for subclassing because it nicely allows for superclassing with 'is Tree | Dog'. Again, so that I'm clear--this is your preference, and is not derived from any authoritative source, correct? This might dispatch correctly for 'pure' Trees, Dogs etc. but not for your mixed classes above. As I noted above, Dog is not 'pure' by the definition I know so I'm not sure what to make of this statement. --Dks
Re: Junctions of classes, roles, etc.
David Storrs writes: On Mon, May 02, 2005 at 06:49:10PM +0200, Thomas Sandla wrote: David Storrs wrote: class Tree { method bark() { die Cannot instantiate a Tree--it is abstract! } } class Birch { method bark() { return White, papery } } class Oak { method bark() { return Dark, heavy } } class Dog { method bark() { print Woof, woof!; return bow wow } } class AlienBeastie isa Tree isa Dog {} Here you get an error/warning of a composition time conflict between Tree::bark and Dog::bark. So that I'm clear, is this your opinion/preference or is it based on material from the SEAs? If the latter, could you point me to the relevant passage? As has been pointed out, there's no composition going on. But we are getting rid of search order problems, so you'll get an ambiguous method call error at some point. Whether this is at the time you create the class or the time you try to call the method, I do not know. My preferred syntax for multiple inheritance is the junctive notation 'is Tree Dog' for subclassing because it nicely allows for superclassing with 'is Tree | Dog'. Again, so that I'm clear--this is your preference, and is not derived from any authoritative source, correct? Not authoritative. I, for one, really want the ability to superclass a posteriori, but I'm not sure this is how you do it. Luke
Re: Junctions of classes, roles, etc.
On Sat, 2005-04-30 at 16:55 -0700, Brent 'Dax' Royal-Gordon wrote: Aaron Sherman [EMAIL PROTECTED] wrote: On Sat, 2005-04-30 at 22:24 +0800, Autrijus Tang wrote: That would be absolutely horrible. Str|Int is simply the type of Yes|1, isn't it? That would certainly make signature matching on different kinds of junctive types trivial. Nope. You all seem to have some very strong opinions, and I'm unable to have a discussion around absolutes like absolutely horrible and nope, so all hypotheticals aside, I'll just concede that this is an uninteresting way to spend our time.
Re: Junctions of classes, roles, etc.
On Sun, May 01, 2005 at 10:59:59AM -0400, Aaron Sherman wrote: On Sat, 2005-04-30 at 16:55 -0700, Brent 'Dax' Royal-Gordon wrote: Aaron Sherman [EMAIL PROTECTED] wrote: On Sat, 2005-04-30 at 22:24 +0800, Autrijus Tang wrote: That would be absolutely horrible. You all seem to have some very strong opinions, and I'm unable to have a discussion around absolutes like absolutely horrible and nope, so all hypotheticals aside, I'll just concede that this is an uninteresting way to spend our time. Sorry. I'll watch my language better in the future, and provide better rationales to support my opinion. :-/ In this case, the reason I called this absolutely horrible: my Str|Int $x; $x.method(); # calls .method twice Is because to me, it is conceptually no difference to: sub foo (Str|Int $x) { $x.method() }; In both cases, the junctive type is used to construct a new type that is a supertype of both Str and Int, for type checking purposes. If it silently promotes the variable itself to a Junction for autothreading, that will render such type construction unusable, as it will be doing two highly orthogonal things with a single syntax. Again, my apologies for using strong words without adequate justification. Thanks, /Autrijus/ pgpvkCR2varmo.pgp Description: PGP signature
Re: Junctions of classes, roles, etc.
On Sat, Apr 30, 2005 at 09:13:26AM -0500, Abhijit Mahabal wrote: On Fri, 29 Apr 2005, Brent 'Dax' Royal-Gordon wrote: David Storrs [EMAIL PROTECTED] wrote: Could we see some code that shows why this is a good idea? My initial reaction is horror; I can very easily see huge numbers of subtle, hard-to-reproduce bugs coming out of this. I'm quite willing to believe that there are [good results], but I'm not coming up with them. What do you think this is? sub foo(Str | Int $bar) { ... } I believe you mean sub foo(Str^Int $bar){...} ( something that is Int or Str but not both). But that, too, just reduces the amount of code and is merely a shortcut for: multi sub(Str $bar){...} multi sub(Int $bar){...} I do not see how any auto-threading occurs in that code. It is completely innocuous in that sense, and I don't think that is what horrified David. Indeed, you're right on the money, Abhijit. Thanks for stating it so well. Let's move this away from simple types like Str and Int for a moment. Tell me what this does: class Tree { method bark() { die Cannot instantiate a Tree--it is abstract! } } class Birch { method bark() { return White, papery } } class Oak { method bark() { return Dark, heavy } } class Dog { method bark() { print Woof, woof!; return bow wow } } class AlienBeastie isa Tree isa Dog {} class WhiteAlienBeastie isa Birch isa Dog {} class HeavyAlienBeastie isa Oak isa Dog {} sub Foo(Tree|Dog $x) { $x.bark() } Ignore for the moment that this is stupid code--it's semantically and (AFAIK) syntactically valid. So, what happens when I do each of these: Foo( new AlienBeastie() ); Foo( new WhiteAlienBeastie() ); Foo( new HeavyAlienBeastie() ); ?? --Dks
Re: Junctions of classes, roles, etc.
On Fri, 29 Apr 2005, Brent 'Dax' Royal-Gordon wrote: David Storrs [EMAIL PROTECTED] wrote: On Thu, Apr 28, 2005 at 03:28:41PM +0200, Ingo Blechschmidt wrote: so we had junctions of Code references some days ago, what's with junctions of Class and Role objects? :) Could we see some code that shows why this is a good idea? My initial reaction is horror; I can very easily see huge numbers of subtle, hard-to-reproduce bugs coming out of this. On the other hand, I do not immediately see major applications...most of what I can see is things that reduce the amount of code needed, but don't actually accomplish anything fundamentally new. What do junctions of Class|Role objects give us that can't be achieved in other ways? I'm quite willing to believe that there are such things, but I'm not coming up with them. What do you think this is? sub foo(Str | Int $bar) { ... } I believe you mean sub foo(Str^Int $bar){...} ( something that is Int or Str but not both). But that, too, just reduces the amount of code and is merely a shortcut for: multi sub(Str $bar){...} multi sub(Int $bar){...} I do not see how any auto-threading occurs in that code. It is completely innocuous in that sense, and I don't think that is what horrified David. What was troublesome was, I think: my Str|Int $x; $x.foo(); # runs two methods and returns a junction I would like to be able to read the above code to mean: type X ::= Scalar where Str|Int; my X $x; # $x = non int/non string now a runtime error $x.foo(); # no different from if you had just said my $x Feel free to tell me I am barking up the wrong tree if that is what I am doing. --abhijit
Re: Junctions of classes, roles, etc.
On Sat, 2005-04-30 at 22:24 +0800, Autrijus Tang wrote: On Sat, Apr 30, 2005 at 09:13:26AM -0500, Abhijit Mahabal wrote: I do not see how any auto-threading occurs in that code. It is completely innocuous in that sense, and I don't think that is what horrified David. What was troublesome was, I think: my Str|Int $x; $x.foo(); # runs two methods and returns a junction That would be absolutely horrible. Then tell me what $!.can(chars) returns, assuming that $! is implemented as an any junction of Int and Str values? My take would be that it returns false|true, which is true in a boolean context, but feel free to talk me out of it. Str|Int is simply the type of Yes|1, isn't it? That would certainly make signature matching on different kinds of junctive types trivial. I would like to be able to read the above code to mean: type X ::= Scalar where Str|Int; my X $x; # $x = non int/non string now a runtime error $x.foo(); # no different from if you had just said my $x This is my current understanding in the implementation. That's not a junction, and thus should not use junction syntax. I'm not opposed to having such a construct, but re-using junction syntax is going to cause massive headaches for anyone trying to learn the language. Also, what is: $x = ::(Int) | ::(Str) my ::($x) $y; at which stages of the execution of that code? Are you saying that $x does not contain a junction, or that a junction used as a type does not create a junction value? If the latter, then what is the type of Yes|1?
Re: Junctions of classes, roles, etc.
On Sat, 30 Apr 2005, Aaron Sherman wrote: On Sat, 2005-04-30 at 22:24 +0800, Autrijus Tang wrote: On Sat, Apr 30, 2005 at 09:13:26AM -0500, Abhijit Mahabal wrote: I do not see how any auto-threading occurs in that code. It is completely innocuous in that sense, and I don't think that is what horrified David. What was troublesome was, I think: my Str|Int $x; $x.foo(); # runs two methods and returns a junction That would be absolutely horrible. Then tell me what $!.can(chars) returns, assuming that $! is implemented as an any junction of Int and Str values? If $! were explicitely Yes|1, then I agree that it returns false|true. I believe that in the code you wrote.. $x = ::(Int) | ::(Str) my ::($x) $y; $x is a junction, and $y is not a junction. type, to me, is just a sticky note attched to an object. I would not like to see autothreading on every junctive sticky. In the code above, if there were a method called .type(), then $y.type() would indeed return a junction, but not by running two methods and orring their output. Str|Int is simply the type of Yes|1, isn't it? Hmmm... I am not sure. Maybe the type is just Junc or something. Str|Int is also the type of 7 and of yes. Moreover, if the return type of a method is junctive, would you want that menthod to autothread too? --abhijit Abhijit Mahabal http://www.cs.indiana.edu/~amahabal/
Re: Junctions of classes, roles, etc.
Aaron Sherman [EMAIL PROTECTED] wrote: On Sat, 2005-04-30 at 22:24 +0800, Autrijus Tang wrote: On Sat, Apr 30, 2005 at 09:13:26AM -0500, Abhijit Mahabal wrote: I do not see how any auto-threading occurs in that code. It is completely innocuous in that sense, and I don't think that is what horrified David. What was troublesome was, I think: my Str|Int $x; $x.foo(); # runs two methods and returns a junction That would be absolutely horrible. Then tell me what $!.can(chars) returns, assuming that $! is implemented as an any junction of Int and Str values? My take would be that it returns false|true, which is true in a boolean context, but feel free to talk me out of it. `$!` is an `Exception` (or somesuch) object, not a `Str|Int`, but in general, that depends on the contents of the variable. If a Str|Int was assigned a `Str`, `can` would be true; if it were assigned an `Int`, `can` would be false. If it were assigned a disjunction of a `Str` and an `Int`, it'd return `true|false`, which evaluates to `true`. Str|Int is simply the type of Yes|1, isn't it? That would certainly make signature matching on different kinds of junctive types trivial. Nope. The type `Str|Int` doesn't mean this variable contains a disjunction of `Str`s and `Int`s; it means This variable can contain either a `Str` or an `Int`. (Actually, it means this variable can contain anything consistent with a Str or Int, which also includes subclasses and certain junctions.) When you see a declaration like: my Foo $bar; Think of it as being like: my $bar where { $_ ~~ Foo }; If the latter, then what is the type of Yes|1? I suspect it's `Disjunction of Str | Int`. -- Brent 'Dax' Royal-Gordon [EMAIL PROTECTED] Perl and Parrot hacker I used to have a life, but I liked mail-reading so much better.
Re: Junctions of classes, roles, etc.
On Thu, Apr 28, 2005 at 03:28:41PM +0200, Ingo Blechschmidt wrote: so we had junctions of Code references some days ago, what's with junctions of Class and Role objects? :) Could we see some code that shows why this is a good idea? My initial reaction is horror; I can very easily see huge numbers of subtle, hard-to-reproduce bugs coming out of this. On the other hand, I do not immediately see major applications...most of what I can see is things that reduce the amount of code needed, but don't actually accomplish anything fundamentally new. What do junctions of Class|Role objects give us that can't be achieved in other ways? I'm quite willing to believe that there are such things, but I'm not coming up with them. --Dks
Re: Junctions of classes, roles, etc.
David Storrs [EMAIL PROTECTED] wrote: On Thu, Apr 28, 2005 at 03:28:41PM +0200, Ingo Blechschmidt wrote: so we had junctions of Code references some days ago, what's with junctions of Class and Role objects? :) Could we see some code that shows why this is a good idea? My initial reaction is horror; I can very easily see huge numbers of subtle, hard-to-reproduce bugs coming out of this. On the other hand, I do not immediately see major applications...most of what I can see is things that reduce the amount of code needed, but don't actually accomplish anything fundamentally new. What do junctions of Class|Role objects give us that can't be achieved in other ways? I'm quite willing to believe that there are such things, but I'm not coming up with them. What do you think this is? sub foo(Str | Int $bar) { ... } Or this one, which is even more important? sub foo(Any | Junction $bar) { ... } -- Brent 'Dax' Royal-Gordon [EMAIL PROTECTED] Perl and Parrot hacker I used to have a life, but I liked mail-reading so much better.
Re: [S29] pick on other things than junctions
Ingo Blechschmidt iblech at web.de writes: then it has a better chance of working, presuming someone has the gumption to write .pick on hashes, which doesn't look entirely trivial to do right. thinking out loudI'm sure I overlooked something, but the following seems to be correct and is not *that* difficult :): class Hash; ...; method pick() is rw { # First pick a random key. my $key = .keys.pick; # Then return an appropriate Proxy object: return new Proxy: FETCH = { Ok. While typing the C{ here, I realized you were correct :) It'd be reasonable simple if there was a .get_pair_by_key method (which'd do appropriate binding and'd be Cis rw): method pick() is rw { my $key = .keys.pick; my $pair := .get_pair_by_key($key); return $pair; } well :) # Ignoring multi-dimensionality method pairbykey($key is copy) is rw { return new Proxy: FETCH = - $pair { $self{$key} }, STORE = - $pair { my ($newkey, $newval) = $pair.kv; $self.delete($key); # Delete old entry $self{$key = $newkey} = $newval; # Add new entry }; } # Correct? BTW, this would make the following work, too: for %hash.pairs - $pair is rw { $pair = ... } # Implementation of Hash::pairs: method pairs (Any|Junction [EMAIL PROTECTED]) { my @keys = @keytests ?? .keys.grep:{ $_ ~~ any @keytests } :: .keys; return .pairbykey.(@keys); } # Correct? The next logical step to full rw-ness would be a rw .pairs (@keytests removed for simplicity): method pairs ($self:) is rw { return new Proxy: FETCH = { .pairbykey.(.keys) }, STORE = - [EMAIL PROTECTED] { .delete($_) for .keys; # [Is there a .clear? The obvious way, %hash = ()/ # $self = {} won't work of course.] $self{$_.key} = $_.value for @new; }; } # Correct? /thinking out loud --Ingo -- Linux, the choice of a GNU | Mr. Cole's Axiom: The sum of the generation on a dual AMD | intelligence on the planet is a constant; Athlon!| the population is growing.
Junctions of classes, roles, etc.
Hi, so we had junctions of Code references some days ago, what's with junctions of Class and Role objects? :) role A { method foo() { 42 } } role B { method foo() { 23 } } class Test does A|B {} my Test $test .= new; my $ret = $test.foo; # 42|23? role A {} role B { method foo() { 42 } } class Test does A|B {} my Test $test .= new; my $ret = $test.foo; # unthrown-exception undef|42? --Ingo -- Linux, the choice of a GNU | Knowledge is that which remains when what generation on a dual AMD | is learned is forgotten. - Mr. King Athlon!|
Re: Junctions of classes, roles, etc.
Ingo Blechschmidt wrote: Hi, so we had junctions of Code references some days ago, what's with junctions of Class and Role objects? :) I like them! In the type lattice A|B is the lub (lowest upper bound) of A and B. And AB is the glb (greatest lower bound) of A and B. Both are cases of multiple inheritance with possible conflicts. But A|B is more general than each of A and B, while AB is more specific than both. role A { method foo() { 42 } } role B { method foo() { 23 } } class Test does A|B {} Here you have to implement Test::foo. Not doing so is a compile time error---or more precisly a class composition time error. my Test $test .= new; my $ret = $test.foo; # 42|23? Whatever Test::foo returns. role A {} role B { method foo() { 42 } } class Test does A|B {} Here is no conflict, but it might be necessary to implement the more general behaviour. my Test $test .= new; my $ret = $test.foo; # unthrown-exception undef|42? No, $ret == 42 unless Test::foo() is implemented and returns something else. Regards, -- TSa (Thomas Sandlaß)
Re: Junctions of classes, roles, etc.
On Thu, 2005-04-28 at 09:51, Thomas Sandlaß wrote: Ingo Blechschmidt wrote: Hi, so we had junctions of Code references some days ago, what's with junctions of Class and Role objects? :) I like them! In the type lattice A|B is the lub (lowest upper bound) of A and B. And AB is the glb (greatest lower bound) of A and B. That's not at all intuitively obvious because what you're describing is not a junction. At least it doesn't seem like one to me (you're describing a situation where the new class has a specific kind of inheritance, not the situation where it's first ancestor is either all or one of a set). The difference being that in the case of: class x is yz {} my x $a; $a.foo(); The method foo will be invoked from both y and z simultaneously, without conflict, and return a junction of the two results. role A { method foo() { 42 } } role B { method foo() { 23 } } class Test does A|B {} Here you have to implement Test::foo. Not doing so is a compile time error---or more precisly a class composition time error. Let's be clear about why you think that. Roles are not ordered, and thus you must disambiguate the use of more than one. S12 says: There are several ways to solve method conflicts. The first is simply to write a class method that overrides the conflicting role methods, perhaps figuring out which role method to call. Alternately, if the role's methods are declared multi, they can be disambiguated based on their long name. If the roles forget to declare them as multi, you can force a multi on the roles' methods by installing a multi stub in the class being constructed: multi method shake {...} However, this is a junction, so: class Test does A|B is really saying that you compose two different classes called Test, which you refer to singly through the magic of junctions. One Test is composed of the base Test class plus A, and another is composed of the base Test class plus B (well A plus Test and B plus Test if you think of it in terms of which overrides which). Now, I'm not saying that that's the way it MUST be, just that that seems to be the way that junctions would work in that situation. If we decide that | and aren't really junction constructors in class/role definitions, then we can make them whatever we want. -- Aaron Sherman [EMAIL PROTECTED] Senior Systems Engineer and Toolsmith It's the sound of a satellite saying, 'get me down!' -Shriekback
Re: Junctions of classes, roles, etc.
Aaron Sherman wrote: Now, I'm not saying that that's the way it MUST be, just that that seems to be the way that junctions would work in that situation. I know, and I'm very confused about all these pseudo procedural uses of junctions. And others seem to share my state of affairs. If we decide that | and aren't really junction constructors in class/role definitions, then we can make them whatever we want. Ohh, yes please! Actually I see the biggest potential of junctions in the type system. E.g. the comparison operator = could get return type -1^0^1. This is first of all good documentation and secondly preserves valuable information for the optimizer. The none() junction is most usefull for excluding types---e.g junctions. So, in the extreme Perl6 might have a junctive type calculation overlaying the value calculation. Thus when a junctive class is needed the class composer can be triggered to make an instance thereof. As you pointed out that might be possible and then continue to MMD with that newly created class. Sounds very dynamic too me. And I've not heard about a language that throws exceptions that say Can't create class Foo does A|B because of conflicting methods bar(). Regards, -- TSa (Thomas Sandlaß)
Re: Calling junctions of closures
Brad Bowman wrote: my $a = rand(); # runtime variable my $result = one(any( sub { $a+1}, sub { $a-1} ),sub { $a+3 }).(); say $result.perl; If $a was 0.5 I'd guess $result = one(any(1.5, 0.5), 3.5) is this the case? IIRC the .perl method produces a string from which an equal value can be recreated, so e.g. $result == eval( $result.perl ). This forces a once through evaluation of the junction. So, yes I think your result is one of the possible 4. The other three are the two numbers in the any() swapped and the number and the any() of the one() swapped. OTOH, the junctions will be stored before the .perl call as e.g. one(any(Ref of Sub, Ref of Sub), Ref of Sub) with the three subs beeing mutually different. The .perl method might then just be propagated down to give e.g. 'sub { $a + 1 }' and not call the subs. But I've no idea how a closed over value is printed. So it could also be 'sub { \0.5 + 1 }' or 'sub { $Full::Path::To::a + 1 }'. This is coupled with the questions how references work and how they are printed. What I don't like of the Junctive Debates is that many people think about junctions as specific forms of list. And I haven't managed to understand the relation between MMD and the code warping needed to get autothreaded junctions. -- TSa (Thomas Sandlaß)
Calling junctions of closures
Hi, Assuming this is allowed, what will the .() calls below return? Does the result depend on the calling context? use junctions; # still required? my @subs = ( sub { return 1 } , sub { return 2 } ); # call the closures in the junction any(@subs).(); all(@subs).(); one(@subs).(); none(@subs).(); one(any(@subs),sub { ... }).(); I'd guess the rule is call 'em all and return a similarly structured junction. How far off the mark am I? On Fri, 2005-02-11 at 10:46 +1100, Damian Conway wrote: Subject: Re: Fwd: Junctive puzzles. Junctions have an associated boolean predicate that's preserved across operations on the junction. Junctions also implicitly distribute across operations, and rejunctify the results. Brad PS. Pugs 6.2.0 currently gets confused: pugs: cannot cast from VJunc any(SubRoutine(anon),SubRoutine(anon)) to AST.VCode -- The occurrence of mysteries is alway by word of mouth. -- Hagakure
Re: Calling junctions of closures
Brad Bowman wrote: Assuming this is allowed, what will the .() calls below return? Does the result depend on the calling context? ... one(any(@subs),sub { ... }).(); Starting to argument from the statement that junctions are values the above plays in the league of 3.() which might not have observeable side effects other then busying the compiler for a while. Actually it could be optimised away :) I'd guess the rule is call 'em all and return a similarly structured junction. How far off the mark am I? Unless you ask a question nothing is called. So at least you need something like if one(...) {...}. Then the call order is undefined and might stop after the first success. Knowing about the constness of the return values of the subs referred to from the junction, and knowing that none of their values is false, these cases might be optimized towards the front when this stops the influx of further interrogation by the if. The reverse might apply for interrogation by unless---but that's up to the oracle :) -- TSa (Thomas Sandlaß)
junctions as indicies
I'm looking in S09, and reading about junctions. It seems to me that if we have a junction $j which we use to index into an array or a hash, it should DWIM and return a junction of the corresponding values. @ar=[1..10]; %hash=(a=1,b=4,c=7); $j=1|2|3; $k=a|c; $u = @ar[$j]; # 2|3|4 $v = %hash{$k}; # 1|7 Does this make sense to others? David
Re: junctions as indicies
David Christensen writes: I'm looking in S09, and reading about junctions. It seems to me that if we have a junction $j which we use to index into an array or a hash, it should DWIM and return a junction of the corresponding values. @ar=[1..10]; %hash=(a=1,b=4,c=7); $j=1|2|3; $k=a|c; $u = @ar[$j]; # 2|3|4 $v = %hash{$k}; # 1|7 Does this make sense to others? Well, if we replaced @ar[$j] with, say, @ar.get($j), what you're proposing happens automatically. So I think that it's the right thing to do. Luke
Re: junctions as indicies
--- David Christensen [EMAIL PROTECTED] wrote: I'm looking in S09, and reading about junctions. It seems to me that if we have a junction $j which we use to index into an array or a hash, it should DWIM and return a junction of the corresponding values. @ar=[1..10]; %hash=(a=1,b=4,c=7); $j=1|2|3; $k=a|c; $u = @ar[$j]; # 2|3|4 $v = %hash{$k}; # 1|7 Does this make sense to others? David Maybe, but I don't like returning junctures in those cases unless you *explicitly* ask for it. I'd rather the default be the arbitrary lists returned, or whatever fits the context. How about @ar=[a..z]; %hash=(a=1,b=4,c=7); $j=1|2|3; $k=a|c; @u = @ar[$j];# (b..d) %u = @ar[$j].kv; # (1='b',2='c',3='d') $u = @ar[$j];# \(b..d) $ju = juncture @ar[$j]; # 'b'|'c'|'d' @v = %hash{$k}; # (1,7) %v = %hash{$k}.kv; # (a=1,c=7) $v = %hash{$k}; # \(1,7) $jv = juncture %hash{$k}; # 1|7 Am I way off base here? __ Do you Yahoo!? Plan great trips with Yahoo! Travel: Now over 17,000 guides! http://travel.yahoo.com/p-travelguide
Re: junctions as indicies
Paul Hodges writes: Maybe, but I don't like returning junctures in those cases unless you *explicitly* ask for it. I'd rather the default be the arbitrary lists returned, or whatever fits the context. How about @ar=[a..z]; %hash=(a=1,b=4,c=7); $j=1|2|3; @j = (1,2,3); $k=a|c; @k = a c; @u = @ar[$j];# (b..d) @u = @[EMAIL PROTECTED]; etc. Perl can indeed slice using ordinary lists. Another problem with using junctions for this is that they're unordered, and you're expecting ordered results back. Luke
Re: junctions as indicies
Paul Hodges wrote: --- David Christensen [EMAIL PROTECTED] wrote: I'm looking in S09, and reading about junctions. It seems to me that if we have a junction $j which we use to index into an array or a hash, it should DWIM and return a junction of the corresponding values. @ar=[1..10]; %hash=(a=1,b=4,c=7); $j=1|2|3; $k=a|c; $u = @ar[$j]; # 2|3|4 $v = %hash{$k}; # 1|7 Does this make sense to others? David Maybe, but I don't like returning junctures in those cases unless you *explicitly* ask for it. I'd rather the default be the arbitrary lists returned, or whatever fits the context. How about @ar=[a..z]; %hash=(a=1,b=4,c=7); $j=1|2|3; $k=a|c; @u = @ar[$j];# (b..d) %u = @ar[$j].kv; # (1='b',2='c',3='d') $u = @ar[$j];# \(b..d) $ju = juncture @ar[$j]; # 'b'|'c'|'d' @v = %hash{$k}; # (1,7) %v = %hash{$k}.kv; # (a=1,c=7) $v = %hash{$k}; # \(1,7) $jv = juncture %hash{$k}; # 1|7 Am I way off base here? What would you propose @v[all(any(4,5),one(1,2,3),none(7,8,9))] return? -- Rod Adams
S03 Precedence for junctions
Hi all, S03 gives infix + a higher precedence than junctive operators in the listed table, but that seems to contradict the examples under Junctive operators. The relevant parts of S03 are: Junctive operators 1|2|3 + 4; # 5|6|7 1|2 + 34; # (4|5) (5|6) Precedence multiplicative * / % x xx + + + ~ ~ ~ additive+ - ~ +| +^ ~| ~^ junctive and (all) junctive or (any) | ^ (1|2|3) + 4 = 5|6|7 but if + is higher precedence than | 1|2|(3 + 4) = 1|2|7 pugs produces 1|2|7 currently, in keeping with S03 In this case is seems like raising junctive ops higher would be correct, but there more to it? Brad -- After reading books and the like it is best to burn them or throw them away. -- Hagakure http://bereft.net/hagakure/
Re: S03 Precedence for junctions
On Sun, Apr 17, 2005 at 08:56:46PM +1000, Brad Bowman wrote: : : Hi all, : : S03 gives infix + a higher precedence than junctive : operators in the listed table, but that seems to contradict : the examples under Junctive operators. The table is correct, and the examples are wrong. : The relevant parts of S03 are: : : Junctive operators : 1|2|3 + 4; # 5|6|7 : 1|2 + 34; # (4|5) (5|6) : : Precedence :multiplicative * / % x xx + + + ~ ~ ~ :additive+ - ~ +| +^ ~| ~^ :junctive and (all) :junctive or (any) | ^ : : : (1|2|3) + 4 = 5|6|7 but if + is higher precedence than | : 1|2|(3 + 4) = 1|2|7 : : pugs produces 1|2|7 currently, in keeping with S03 : : In this case is seems like raising junctive ops higher would : be correct, but there more to it? We spent a goodly long time discussing this very topic in one of our design meetings. The intent of junctions is primarily to produce superposed data values, not to make it possible to write impenetrable code, so the question boils down to whether operators like + are used more often to build the sorts of data values you'd want to |, or whether | is used to build junctions that you'd want to +. We decided that the examples like 1|2|3 + 4; # 5|6|7 1|2 + 34; # (4|5) (5|6) were in fact highly artificial, and people would much more often be using simple operators to compose alternative values: $a + 1 | $a - 1 That was our gut-level feeling. A lot of this design stuff comes down to just that. So we could be completely and utterly wrong about it. Larry
Re: S03 Precedence for junctions
On Sun, Apr 17, 2005 at 07:29:33AM -0700, Larry Wall wrote: On Sun, Apr 17, 2005 at 08:56:46PM +1000, Brad Bowman wrote: : : Hi all, : : S03 gives infix + a higher precedence than junctive : operators in the listed table, but that seems to contradict : the examples under Junctive operators. The table is correct, and the examples are wrong. Examples are now fixed in S03.pod in the svn repository. Pm
Re: [S29] pick on other things than junctions
Hi, Trey Harris wrote: In a message dated Mon, 4 Apr 2005, Ingo Blechschmidt writes: What does pick return on hashes? Does it return a random value or a random pair? (I suppose returning a pair is more useful.) I'd assume in all cases that pick returns an *alias*, and in the case of hashes, an alias to the pair: # Add entropy to your hash for 1..$entropy_thresshold { %hash.pick.value *= rand $scribble_factor; } I like that, too. So: my @array = a b c d; my $elem = @array.pick; $elem = z; # $elem now z, @array unchanged my @array = a b c d; my $elem := @array.pick; $elem = z; # $elem now z, @array changed # (any(@array) eq z now true) Same for hashes: my %hash = (a = 1, b = 2); my $pair = %hash.pick; $pair = ...; # %hash unchanged my %hash = (a = 1, b = 2), my $pair := %hash.pick; $pair = ...; # %hash changed --Ingo -- Linux, the choice of a GNU | Black holes result when God divides the generation on a dual AMD | universe by zero. Athlon!|
Re: [S29] pick on other things than junctions
On Tue, Apr 05, 2005 at 02:38:05PM +0200, Ingo Blechschmidt wrote: : Hi, : : Trey Harris wrote: : In a message dated Mon, 4 Apr 2005, Ingo Blechschmidt writes: : What does pick return on hashes? Does it return a random value or a : random pair? (I suppose returning a pair is more useful.) : : I'd assume in all cases that pick returns an *alias*, and in the case : of hashes, an alias to the pair: : :# Add entropy to your hash :for 1..$entropy_thresshold { :%hash.pick.value *= rand $scribble_factor; :} : : I like that, too. So: : my @array = a b c d; : my $elem = @array.pick; : $elem = z; # $elem now z, @array unchanged : : my @array = a b c d; : my $elem := @array.pick; : $elem = z; # $elem now z, @array changed :# (any(@array) eq z now true) But what should we call pick without replacment? .peck? Unfortunately @array.=pick isn't what you want. It would reduce the array to one element. On the other hand, if .pick takes an argument saying how many to pick, then maybe @array.=pick([EMAIL PROTECTED]) gives you a random shuffle. Unfortunately, @array.=pick(@array - 1) won't tell you which one it left out. : Same for hashes: : my %hash = (a = 1, b = 2); : my $pair = %hash.pick; : $pair = ...; # %hash unchanged : : my %hash = (a = 1, b = 2), : my $pair := %hash.pick; : $pair = ...; # %hash changed I'm not sure that works. We don't quite have pairs as first class containers. Binding would try to use a pair as a named argument, and would fail unless the key happened to be 'pair', which it isn't in this case. However, if you were to say, my Pair $pair := %hash.pick; then it has a better chance of working, presuming someone has the gumption to write .pick on hashes, which doesn't look entirely trivial to do right. Larry
Re: [S29] pick on other things than junctions
Hi, Larry Wall wrote: : Same for hashes: [...] : my %hash = (a = 1, b = 2), : my $pair := %hash.pick; : $pair = ...; # %hash changed I'm not sure that works. We don't quite have pairs as first class containers. Binding would try to use a pair as a named argument, and would fail unless the key happened to be 'pair', which it isn't in this case. Oh yes, of course. Others may be interested in http://groups.google.com/groups?threadm=x7wtsvo0fs.fsf%40mail.sysarch.com. then it has a better chance of working, presuming someone has the gumption to write .pick on hashes, which doesn't look entirely trivial to do right. thinking out loudI'm sure I overlooked something, but the following seems to be correct and is not *that* difficult :): class Hash; ...; method pick() is rw { # First pick a random key. my $key = .keys.pick; # Then return an appropriate Proxy object: return new Proxy: FETCH = { Ok. While typing the C{ here, I realized you were correct :) It'd be reasonable simple if there was a .get_pair_by_key method (which'd do appropriate binding and'd be Cis rw): method pick() is rw { my $key = .keys.pick; my $pair := .get_pair_by_key($key); return $pair; } --Ingo -- Linux, the choice of a GNU | Mathematicians practice absolute freedom. generation on a dual AMD | -- Henry Adams Athlon!|
[S29] pick on other things than junctions
Hi, I remembered Damian saying that pick does not only work on junctions, but on arrays and hashes, too (and I even found his posting :): http://groups.google.com/groups?selm=420DB295.3000902%40conway.org). Are the following assumptions correct? my $junc = 1|2|3; print $junc.pick; # 1, 2, or 3 print pick $junc; # same my @array = a b c; print @array.pick; # a, b, or c print pick @array; # same What does pick return on hashes? Does it return a random value or a random pair? (I suppose returning a pair is more useful.) --Ingo -- Linux, the choice of a GNU | The next statement is not true. The generation on a dual AMD | prevoius statement is true. Athlon!|
Re: [S29] pick on other things than junctions
Ingo Blechschmidt wrote: I remembered Damian saying that pick does not only work on junctions, but on arrays and hashes, too (and I even found his posting :): http://groups.google.com/groups?selm=420DB295.3000902%40conway.org). Are the following assumptions correct? my $junc = 1|2|3; print $junc.pick; # 1, 2, or 3 print pick $junc; # same my @array = a b c; print @array.pick; # a, b, or c print pick @array; # same What does pick return on hashes? Does it return a random value or a random pair? (I suppose returning a pair is more useful.) Most likely a pair. Now if I could only find some more time to work on S29. I've been making progress (slowly) on getting the string functions written up, but life seems to be conspiring against rapid progress. -- Rod Adams
Re: [S29] pick on other things than junctions
In a message dated Mon, 4 Apr 2005, Ingo Blechschmidt writes: What does pick return on hashes? Does it return a random value or a random pair? (I suppose returning a pair is more useful.) I'd assume in all cases that pick returns an *alias*, and in the case of hashes, an alias to the pair: # Add entropy to your hash for 1..$entropy_thresshold { %hash.pick.value *= rand $scribble_factor; } Trey
Re: [S29] pick on other things than junctions
I'd assume you'd get an *alias* to a random pair: # Test error-correction for 1..$entropy_threshhold { %hash.pick.value = rand $scribble_factor; } Trey In a message dated Mon, 4 Apr 2005, Ingo Blechschmidt writes: Hi, I remembered Damian saying that pick does not only work on junctions, but on arrays and hashes, too (and I even found his posting :): http://groups.google.com/groups?selm=420DB295.3000902%40conway.org). Are the following assumptions correct? my $junc = 1|2|3; print $junc.pick; # 1, 2, or 3 print pick $junc; # same my @array = a b c; print @array.pick; # a, b, or c print pick @array; # same What does pick return on hashes? Does it return a random value or a random pair? (I suppose returning a pair is more useful.) --Ingo --
Re: [S29] pick on other things than junctions
In a message dated Mon, 4 Apr 2005, Ingo Blechschmidt writes: What does pick return on hashes? Does it return a random value or a random pair? (I suppose returning a pair is more useful.) I'd assume in all cases that pick returns an *alias*, and in the case of hashes, an alias to the pair: # Add entropy to your hash for 1..$entropy_thresshold { %hash.pick.value *= rand $scribble_factor; } Trey
Re: [S29] pick on other things than junctions
Yikes. Sorry about the ressends... my email client kept dying and I thought the mail was lost. Guess not. :-) Trey In a message dated Mon, 4 Apr 2005, Trey Harris writes: In a message dated Mon, 4 Apr 2005, Ingo Blechschmidt writes: What does pick return on hashes? Does it return a random value or a random pair? (I suppose returning a pair is more useful.) I'd assume in all cases that pick returns an *alias*, and in the case of hashes, an alias to the pair: # Add entropy to your hash for 1..$entropy_thresshold { %hash.pick.value *= rand $scribble_factor; } Trey --
Re: Junctions Question
Stevan Little writes: my $a = 'a'; my $b = ''; my $c = ''; my $any_of_them = $b | $c | $a; # this test passes ok('a' eq $any_of_them, '($b | $c | $a) matches at least one a'); $b = 'b'; $c = 'c'; # this test passes ... ok('a' eq $any_of_them, '($b | $c | $a) matches at least one a'); # but these two tests don't ok('b' eq $any_of_them, '($a | $b | $c) matches at least one b'); ok('c' eq $any_of_them, '($c | $a | $b) matches at least one c'); That behavior is correct. Just as if you said: my $a = 'a'; my $b = $a; $a = 'b'; say $b; # a This should work, however: my $a = 'a'; my $b = ''; my $c = ''; my $any_of_them = \$a | \$b | \$c; $b = 'b'; $c = 'c'; ok('b' eq $$any_of_them); # passes That second $ might not need to be there. I don't understand exactly how transparent references are yet. Luke
Re: SEND + MORE = MONEY (works now in pugs with junctions!)
Rod Adams wrote: I have the philosophical problem with your use of junctions in this context due to the fact that you are completely ignoring the predicate of the junction. The C all(...) == one(...) is an excellent use of YES, and much clearer than when this test is buried under code that has to be written if you only have simple tests and boolean connectives. junctions, that makes use of the predicates when the junctions are evaluated. If you want threading without the predicate, I give you the hyperthreader (well, I'm trying to). I fully agree to this. I interpret the junctions as oracle values: the predicate is used to properly address them when you ask e.g. is any of your values greater than 10?. You shouldn't assume an inner structure. And as Rod points out, many examples are using the inner structure and the auto-threading while *ignoring* the predicate. Regards, -- TSa (Thomas Sandlaß)
Re: Junctions - feedback and desires
Rod Adams [EMAIL PROTECTED] wrote: Well if 10 $j 1 { ... } if 10 $j { if $j 1 { ... }} Could easily wind up with the same opcodes. No. In the first case $j is evaluated just once. In the second case it's evaluated twice. leo
Re: Junctions - feedback and desires
Leopold Toetsch wrote: Rod Adams [EMAIL PROTECTED] wrote: Well if 10 $j 1 { ... } if 10 $j { if $j 1 { ... }} Could easily wind up with the same opcodes. No. In the first case $j is evaluated just once. In the second case it's evaluated twice. You're right. I just dived through the archives and found that chained operators are an exception. Sorry for missing that. Which can be a mess explaining to someone how if 0 $x$x 10 {...} can be true when if 0 $x 10 {...} is false. Though I suppose if we can extend this to a general rule of if it only appears once, it can only be threaded once, it makes a certain amount of sense. -- Rod Adams
Re: SEND + MORE = MONEY (works now in pugs with junctions!)
There's no doubt that the QM view of extended entanglement is very useful. After all, that's what the whole universe runs on. But most mortals will want the classical view to be the default, so we'll require some kind of explicit markup or pragma if you want to extend entanglement further out than comparisons. That's why junctions can't be passed into a function unless the function specifically allows it, for instance. (Then there's the matter of sneaky return values.) The only alternative is to autothread every conditional, and I don't think we'd survive the lynch mobs if we did that. Maybe there's some middle ground here that I don't see, but if so, I don't see it. And if I don't see it, all the other Pooh bears will have trouble with it too. Larry
Re: SEND + MORE = MONEY (works now in pugs with junctions!)
Larry Wall writes: There's no doubt that the QM view of extended entanglement is very useful. After all, that's what the whole universe runs on. But most mortals will want the classical view to be the default, so we'll require some kind of explicit markup or pragma if you want to extend entanglement further out than comparisons. That's why junctions can't be passed into a function unless the function specifically allows it, for instance. (Then there's the matter of sneaky return values.) The only alternative is to autothread every conditional, and I don't think we'd survive the lynch mobs if we did that. Maybe there's some middle ground here that I don't see, but if so, I don't see it. And if I don't see it, all the other Pooh bears will have trouble with it too. The collapsing behavior of Quantum::Entanglement (and what is being expressed as wanted here) is actually a sort of parallel logic programming. Instead of trying and backtracking, it's just doing it all at once. Instead of providing a collpasing junction type which will confuse the heck out of people, I think it's best to concentrate on how we will integrate logic programming in the language. And the best way to concentrate on that at this point might be not to think about it at all. But junctions might be our ticket into the world of logic programming. We'd have to change them, but there are some amazing parallels between what junctions currently do and what regexes do (regexes even use the same symbols) and what my Argument Patterns proposal does with junctive types, which are both logical programming frameworks. So let's put it in the back of our minds. It's going to be in the front of mine for the day, but I might not come up with anything. Luke
Re: SEND + MORE = MONEY (works now in pugs with junctions!)
Sam Vilain wrote: I've changed examples/sendmoremoney.p6 in the pugs distribution to use junctions correctly to demonstrate that they *can* be used to solve these sorts of problems, and that it is just a matter of semantics and writing code correctly. However, poor semantics can make the task of writing optimisers unnecessarily difficult or impractical, as Bourne demonstrated. in short, it seems people want this: my $a = any(1..9); my $b = any(1..9); my $c = any(0..9); if ( $a != $b $b != $c $a != $c ($a + $b == $a * 10 + $c) ) { print $a + $b = $a$c; } To mean this (forgive the duplication of collapse() here): sub collapse($x, $sub) { $sub.($x) } sub collapse($x, $y, $sub) { $sub.($x,$y) } my $a = any(1..9); my $b = any(1..9); my $c = any(0..9); collapse($a, $b, - $a, $b { ($a != $b) collapse($c, - $c { if ( ( $b != $c ) ( $a != $c ) ($a + $b == $a * 10 + $c) ) { say $a + $b = $a$c; } }); }); (and YES THAT WORKS g). Yes, it does work, given the current state of autothreading. Well, you'd need a C use junctions; in order to store a junction in a variable. And I'm not certain if that changes the autothreading behavior of the closures or not. You might have to declare the collapses as: multi sub collapse ($x is none(Junction), $sub) {...}; multi sub collapse ($x is none(Junction), $y is none(Junction), $sub) {...}; to get it to thread correctly. I'm not sure. (Pretty sure you'd need the 'multi' in there). It's also a perfect example of where my hyperthreader operator (it hasn't been nailed down yet what the exact syntax is (or even if it exists), I'm waiting for Damian to get back to continue that thread.) is a better tool than junctions. Assuming we use my »« syntax, SEND+MORE==MONEY could be written as: sub test ($s, $e, $n, $d, $m, $o, $r, $y) { if $s$e$n$d + $m$o$r$e == $m$o$n$e$y all($s,$e,$n,$d,$m,$o,$r,$y) == one($s,$e,$n,$d,$m,$o,$r,$y) { say $s$e$n$d + $m$o$r$e == $m$o$n$e$y; } } test(»1..9«, »0..9«, »0..9«, »0..9«, »1..9«, »0..9«, »0..9«, »0..9«); Using Damian's every() syntax, the last line becomes: test(every(1..9), every(0..9), every(0..9), every(0..9), every(1..9), every(0..9), every(0..9), every(0..9)); It's extremely brute force and inefficient, but it works. I have the philosophical problem with your use of junctions in this context due to the fact that you are completely ignoring the predicate of the junction. The C all(...) == one(...) is an excellent use of junctions, that makes use of the predicates when the junctions are evaluated. If you want threading without the predicate, I give you the hyperthreader (well, I'm trying to). I'll also point out that what you wrote above is a lot more readable as: for 1..9 - $a { for 1..9 - $b { next unless $b == none($a); for 0..9 - $c { next unless $c == none($a, $b); if $a + $b == $a * 10 + $c { say $a + $b = $a$c } } } } I mean, wouldn't it really be nice if you could write stuff like this: my @users is persistent(users.isam); my @accounts is persistent(accounts.isam); my $r_user = any(@user); my $r_account = any(@account); if ( $r_account.user == $r_user ) { say(That junction is:, $r_user); } I'm fairly certain that I'll be writing a Set class if no one beats me to it. use Sets; my @users is persistent(users.isam); my @accounts is persistent(accounts.isam); my $s_validusers = set(@accounts».user) - @users; for values $s_validusers - $user { say $user is a valid user; } $r_user at that point represents only the users which have at least one object in @accounts for which there exists an $r_account with a `user' property that is that $r_user member[*]. The closure would then either be run once, with $r_user still a junction (if the interpreter/`persistent' class was capable of doing so), or once for every matching tuple of ($r_account, $r_user). We're still talking in terms of Set Theory, right? If you want Set Theory.. use Sets. Or use some form of Logical Programming which builds the sets implicitly for you, and does all the filtering and backtracking you're asking for. Both topics have been explored recently. The results of that exploration can be summarized as: - Sets would make a nifty module to have around. - Integrating Logical Programming into Perl needs a lot more thought and effort than will likely happen before 6.0.0. Modules grafting LP into Perl and/or Parrot are welcome. -- Rod Adams
Junctions - feedback and desires
I gave a talk on Perl 6 Junctions at the Thousand Oaks Perl Mongers meeting last night http://www.hcoop.net/~terry/perl/talks/p6-junctions/index.html and two questions/desires came out of it: 1: will it be possible to know which element of a junction is currently being used? E.g.: my @first_set = qw(1 1); my @new_set = qw(1 1.4 1 1 8 1 1 1 0.8); my $any_new_set = any(@new_set); my $any_first_set = any(@first_set); if ( (abs($any_first_set - $any_new_set)) 0.5) { a variation in the readings is too large.say; printf we we examining %d and %d when it happened, $any_new_set.current, $any_first_set.current ; # desired feature } 2: Unless the array of values can be specified lazily, it will not be practical to use Perl 6 Junctions on large datasets. For example I might like to be able to specify a sub ref/closure whose execution yields a new array value or undef when no more values. I.e.: sub mynext { my($age) = $sth-fetchrow_array; $age } my $junction = any(\mynext) ; 3: Do junctions short circuit? I.e., whenever the condition is met, does it continue immediately. Using the example from point #1, can we assume that the body of the then branch will fire when 8 of @new_set is encountered?
Re: Junctions - feedback and desires
Terrence Brannon wrote: I gave a talk on Perl 6 Junctions at the Thousand Oaks Perl Mongers meeting last night http://www.hcoop.net/~terry/perl/talks/p6-junctions/index.html and two questions/desires came out of it: 1: will it be possible to know which element of a junction is currently being used? E.g.: my @first_set = qw(1 1); my @new_set = qw(1 1.4 1 1 8 1 1 1 0.8); my $any_new_set = any(@new_set); my $any_first_set = any(@first_set); if ( (abs($any_first_set - $any_new_set)) 0.5) { a variation in the readings is too large.say; printf we we examining %d and %d when it happened, $any_new_set.current, $any_first_set.current ; # desired feature } I do not believe that is possible. This is the filtering or unification behavior that people keep wanting junctions to have, which they do not. A given junction always has all of the values it was made with. No more, no less. If you want something else, you have to make a new junction. Consider that it's been decided that : $j = 11|0; 10 $j 1 Is true. $j retains the 0 even after the 0 failed a test. As for the current value, there is only a current value during threading. In this example, the threading is fully contained in C (abs($any_first_set - $any_new_set)) 0.5 . By the time the printf comes, the threading is long past. If you wish to change the behavior, you're welcome to put out some proposals. But I'll warn you from experience that Damian is rather stubborn about the current behavior. =) 2: Unless the array of values can be specified lazily, it will not be practical to use Perl 6 Junctions on large datasets. For example I might like to be able to specify a sub ref/closure whose execution yields a new array value or undef when no more values. I.e.: sub mynext { my($age) = $sth-fetchrow_array; $age } my $junction = any(\mynext) ; You now have a junction whose only value is a coderef. I do not believe that you can create a 'lazy junction'. But I don't recall the topic coming up before, so we'll have to wait for Damian to come back unless someone else knows for certain. 3: Do junctions short circuit? I.e., whenever the condition is met, does it continue immediately. Using the example from point #1, can we assume that the body of the then branch will fire when 8 of @new_set is encountered? Yes, they short circuit. However, your second statement might be a bit misleading. When the 8 is encountered, the evaluation of the junctions terminates, and then processing moves on to the next statement, in this case the say. What you said might be construed as the junctions were still being threaded when the the say and printf occurred. HTH, -- Rod Adams
Re: Junctions - feedback and desires
Rod Adams wrote: I do not believe that is possible. This is the filtering or unification behavior that people keep wanting junctions to have, which they do not. Aww! But what about all the great problems that could be expressed with them? I know of two languages that consider this to be a core feature now (Prolog, Oz[1]). A given junction always has all of the values it was made with. No more, no less. If you want something else, you have to make a new junction. Consider that it's been decided that : $j = 11|0; 10 $j 1 Is true. $j retains the 0 even after the 0 failed a test. I can't see how this can be possible with the possibility of autothreading as described in [2]. Maybe the example you suggest is true, if both comparisons happen simultaneously, but what about this one? if ($j 10) { if ($j 1) { say $j took on two values at once; } } Let's say that the implementation chose to implement the first if() by auto-threading. The first thread where $j == 11 succeeds. The second, where $j == 1 fails. In the second thread, $j == 11 fails. It is by this assumption that the example in [3] was built. But wait, isn't (10 $j 1) likely to produce the same opcode tree as if($j10){if($j1){}} ? As for the current value, there is only a current value during threading. Isn't the threading conceptual, and actual threading invoked only when the optimiser has finished using available logic / set theory operations to prevent absurd numbers of threads being made that exit immediately? Sam. References: 1. http://xrl.us/fehh (Link to www.mozart-oz.org) A representation of send+more=money in Oz 2. http://dev.perl.org/perl6/synopsis/S09.html 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. In particular, if a junction is used as an argument to any routine (operator, closure, method, etc.), and the scalar parameter you are attempting to bind the argument to is inconsistent with the Junction type, that routine is autothreaded, meaning the routine will be called automatically as many times as necessary to process the individual scalar elements of the junction in parallel. 3. An implementation of send+more=money using Perl 6 Junctions http://svn.openfoundry.org/pugs/examples/sendmoremoney.p6 http://xrl.us/feis (revision at time of writing this message)
Re: Junctions - feedback and desires
Rod Adams wrote: I do not believe that you can create a 'lazy junction'. But I don't recall the topic coming up before, so we'll have to wait for Damian to come back unless someone else knows for certain. My understanding is that all lists are conceptually lazy. any(2..Inf) is perfectly valid.
Re: Junctions - feedback and desires
Sam Vilain wrote: Rod Adams wrote: I do not believe that is possible. This is the filtering or unification behavior that people keep wanting junctions to have, which they do not. Aww! But what about all the great problems that could be expressed with them? I know of two languages that consider this to be a core feature now (Prolog, Oz[1]). I'm not disputing that it would be powerful. I'm simply saying that as currently defined, junctions do not behave in this fashion. It also does not make a lot of sense to filter out restricting values in a none() junction. And as one who recently proposed a way of getting Prolog like features in Perl (through Rules, not Junctions), I understand the appeal completely. Junctions are not the way to that goal. They are something different. A given junction always has all of the values it was made with. No more, no less. If you want something else, you have to make a new junction. Consider that it's been decided that : $j = 11|0; 10 $j 1 Is true. $j retains the 0 even after the 0 failed a test. I can't see how this can be possible with the possibility of autothreading as described in [2]. because it gets interpreted as: 10 $j 1 -- (10 $j) ($j 1) -- (10 any(0, 11)) (any(0, 11) 1) -- any(10 0, 10 11) any(0 1, 11 1) -- any(false, true) any(true, false) -- true true -- true. Maybe the example you suggest is true, if both comparisons happen simultaneously, but what about this one? if ($j 10) { if ($j 1) { say $j took on two values at once; } } The Csay would occur, even with the first condition as C $j 10 , as you likely intended it to be. Taking multiple values at once is what junctions are all about. People seem to forget the role the predicate plays in junction evaluation. You thread over the different values, gain a result, and then use the predicate to recombine the results into a single scalar. If instead I had said: $j = 11 0; 10 $j 1 it would be false, because C all( true, false) is false. $j itself never changes. It is always a collection of values with a predicate. If you wish to have a junction with different values in it, you have to create a new one. Let's say that the implementation chose to implement the first if() by auto-threading. The first thread where $j == 11 succeeds. The second, where $j == 1 fails. In the second thread, $j == 11 fails. Except that the threadings are indendent of each other. $j = any(0,11); $j != $j; is true. $j != $j -- any(0,11) != any(0,11) -- any(0 != any(0,11), 11 != any(0,11)) -- any(any(0 != 0, 0 != 11), any(11 != 0, 11 != 11)) -- any(any(false, true), any(true, false)) -- any(true, true) -- true Similarly: $j = all(0,11); $j == $j; is false. It is by this assumption that the example in [3] was built. That assumption is in err, and the example does not generate the solutions desired See my response to it in http://www.nntp.perl.org/group/perl.perl6.language/19428 But wait, isn't (10 $j 1) likely to produce the same opcode tree as if($j10){if($j1){}} ? Well if 10 $j 1 { ... } if 10 $j { if $j 1 { ... }} Could easily wind up with the same opcodes. Unless the optimizer saw something in the first one where it could prove C $j 1 is false. As for the current value, there is only a current value during threading. Isn't the threading conceptual, and actual threading invoked only when the optimiser has finished using available logic / set theory operations to prevent absurd numbers of threads being made that exit immediately? The optimizer can skip threading over values that it can prove will not affect the outcome. That's short circuiting. But asking the optimizer to know in advance what is absurd is a tall order. Even without junctions, someone could make $j an object with an overloaded set of compare operators against Num. And there's no way for the compiler to know if those operators are consistent and transitive. (One could hope they were, but you never know). I would not call the threading conceptual. It's a very real thing. 2. http://dev.perl.org/perl6/synopsis/S09.html 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. In particular, if a junction is used as an argument to any routine (operator, closure, method, etc.), and the scalar parameter you are attempting to bind the argument to is inconsistent with the Junction type, that routine is autothreaded, meaning the routine will be called automatically as many times as necessary to process the individual scalar elements of the junction in parallel. In the cases above, the routine being threaded over is the comparison operator, not the surrounding code block that contains it. -- Rod Adams
Re: Junctions - feedback and desires
Dave Whipp wrote: Rod Adams wrote: I do not believe that you can create a 'lazy junction'. But I don't recall the topic coming up before, so we'll have to wait for Damian to come back unless someone else knows for certain. My understanding is that all lists are conceptually lazy. any(2..Inf) is perfectly valid. The list being fed into the junction can be lazy. But I believe that the list gets iterated over completely in the creation of the junction, so C any(2..Inf) is valid, but melts your processor similar to C sort 2..Inf . My impression has been that after the creation of a junction, the values that junction has are set in stone. Allowing some form of lazy list to add values at will seems a bit counter to me. But if @Cabal think it's okay to have lazy junctions, I won't argue with them. -- Rod Adams
Re: Junctions - feedback and desires
RA == Rod Adams [EMAIL PROTECTED] writes: My understanding is that all lists are conceptually lazy. any(2..Inf) is perfectly valid. RA The list being fed into the junction can be lazy. But I believe that RA the list gets iterated over completely in the creation of the RA junction, so C any(2..Inf) is valid, but melts your processor RA similar to C sort 2..Inf . i was under the impression that junctions could be smart about ranges like that and do it correctly. sort can't possibly handle that but some junctions and ranges would work fine. it isn't hard to convert that (with the proper boolean) to a boolean expression internally. RA My impression has been that after the creation of a junction, the RA values that junction has are set in stone. Allowing some form of lazy RA list to add values at will seems a bit counter to me. But if @Cabal RA think it's okay to have lazy junctions, I won't argue with them. lazy only when you can actually cheat IMO. uri -- Uri Guttman -- [EMAIL PROTECTED] http://www.stemsystems.com --Perl Consulting, Stem Development, Systems Architecture, Design and Coding- Search or Offer Perl Jobs http://jobs.perl.org
Re: Junctions - feedback and desires
Rod Adams writes: Dave Whipp wrote: Rod Adams wrote: I do not believe that you can create a 'lazy junction'. But I don't recall the topic coming up before, so we'll have to wait for Damian to come back unless someone else knows for certain. My understanding is that all lists are conceptually lazy. any(2..Inf) is perfectly valid. The list being fed into the junction can be lazy. But I believe that the list gets iterated over completely in the creation of the junction, so C any(2..Inf) is valid, but melts your processor similar to C sort 2..Inf . Well, if we guarantee that .states never returns two of the same value, then of course you can not call .states on an infinite junction. And indeed, while it's possible to do this (taking the range to be an arbitrary infinite list): if any(2...) 100 {...} You'll melt if you do this: if any(2...) 2 {...} We could make junctions smart about ranges, so that the latter can just fail, but I argue that we can only do it well in the simplest of cases. It's probably better not to allow infinite ranges in junctions. On the other hand, if we give junctions well-defined semantics in terms of their underlying lists (such as orderedness), then lazy junctions may be just fine. There's a lot you can do with lazy lists, and there are a lot of very nice idioms having to do with junctions, and I'd like to find a way to make those two things not be mutually exclusive. Luke
SEND + MORE = MONEY (works now in pugs with junctions!)
Rod Adams wrote: And as one who recently proposed a way of getting Prolog like features in Perl (through Rules, not Junctions), I understand the appeal completely. Junctions are not the way to that goal. They are something different. Taking multiple values at once is what junctions are all about. People seem to forget the role the predicate plays in junction evaluation. You thread over the different values, gain a result, and then use the predicate to recombine the results into a single scalar. That assumption is in err, and the example does not generate the solutions desired I've changed examples/sendmoremoney.p6 in the pugs distribution to use junctions correctly to demonstrate that they *can* be used to solve these sorts of problems, and that it is just a matter of semantics and writing code correctly. However, poor semantics can make the task of writing optimisers unnecessarily difficult or impractical, as Bourne demonstrated. in short, it seems people want this: my $a = any(1..9); my $b = any(1..9); my $c = any(0..9); if ( $a != $b $b != $c $a != $c ($a + $b == $a * 10 + $c) ) { print $a + $b = $a$c; } To mean this (forgive the duplication of collapse() here): sub collapse($x, $sub) { $sub.($x) } sub collapse($x, $y, $sub) { $sub.($x,$y) } my $a = any(1..9); my $b = any(1..9); my $c = any(0..9); collapse($a, $b, - $a, $b { ($a != $b) collapse($c, - $c { if ( ( $b != $c ) ( $a != $c ) ($a + $b == $a * 10 + $c) ) { say $a + $b = $a$c; } }); }); (and YES THAT WORKS g). However, the former keeps the optimisation out of the algorithm, so that when someone comes along later with a nice grunty optimiser there is more chance that it gets a go at the entire solution space rather than having to fall back to exhaustive searching. (which might have to find ways to prove associativity of , etc, to make `real' optimisations). I'm trying to see a way that these two ways of using junctions are compatible. As I see it, people want to stretch out the time that the junction is true, to something non-zero, without having to explicitly create all those closures. Getting the old behaviour would be easy, just set a variable in the `if' clause: my $j1 = any(1..5); my $j2 = any(5..9); my $they_equal; if ($j1 == $j2) { # intersection of sets - $j1 and $j2 are any(5), any(5) $they_equal = 1; } else { # symmetric difference of sets - $j1 and $j2 are now # any(1..5), any(5..9) (where $j1 != $j2 :)) } if ($they_equal) { } Now, the `where $j1 != $j2' bit there, which looks like it's on crack, is a way of representing that instead of actually calling that second branch 24 times, it could be calling it with two junctions which are `entangled' (or, if you prefer, `outer joined'). $j1 and $j2 appear almost untouched - except any test that uses $j1 and $j2 together will not see the combination of ($j1 == 5) and ($j2 == 5). I mean, wouldn't it really be nice if you could write stuff like this: my @users is persistent(users.isam); my @accounts is persistent(accounts.isam); my $r_user = any(@user); my $r_account = any(@account); if ( $r_account.user == $r_user ) { say(That junction is:, $r_user); } $r_user at that point represents only the users which have at least one object in @accounts for which there exists an $r_account with a `user' property that is that $r_user member[*]. The closure would then either be run once, with $r_user still a junction (if the interpreter/`persistent' class was capable of doing so), or once for every matching tuple of ($r_account, $r_user). We're still talking in terms of Set Theory, right? One last thing - that comment about any(@foo) == one(@foo) not checking for uniqueness in a list is right - the correct version is: all(@foo) == one(@foo) Sam. Footnotes: * - any relational database `experts' who want to remind me of which normalisation form rules this breaks, please remember that RDBMSes and normalised forms approximate Set Theory, which this is trying to do as well, so I believe such discussion is irrelevant.
Q: Junctions send+more=money
I have two questions about this example code (taken from http://svn.openfoundry.org/pugs/examples/sendmoremoney.p6) (btw, a really nice example of how to use junctions - just try to write this in perl5 :) #!perl6 use v6; my $s; my $e; my $n; my $d; my $m; my $o; my $r; my $y; $s = any(0..10) none(0); $e = any(0..10); $n = any(0..10); $d = any(0..10); $m = any(0..10) none(0); $o = any(0..10); $r = any(0..10); $n = any(0..10); $y = any(0..10); I think these should be any(0..9). my $send := construct($s,$e,$n,$d); my $more := construct($m,$o,$r,$e); my $money := construct($m,$o,$n,$e,$y); if ($send + $more == $money) { say send = $send; say +more = $more; say - say money = $money; } sub foldl(Code op, Any $initial, [EMAIL PROTECTED]) returns Any { if ([EMAIL PROTECTED] == 0) { return $initial; } else { return op(shift @values, ?SUB(op, $initial, @values)); } } sub add(Int $x, Int $y) returns Int { return $x + $y; } sub construct([EMAIL PROTECTED]) returns Junction { return foldl( sub ($x, $y) { $x * 10 + $y}, 0, @values); } How would the if (...) {...} work if there were more than one possible match to this equation? How would I rewrite this example to be more general, so that given 3 strings (in this case 'send', 'more', 'money'), the program would give all possible results for the equation first string + second string = third string. -- Markus Laire Jam. 1:5-6
Re: Q: Junctions send+more=money
Markus Laire wrote: I have two questions about this example code (taken from http://svn.openfoundry.org/pugs/examples/sendmoremoney.p6) I have a few issues with this code. Or at least observations of how it differs from the classic SEND + MORE = MONEY problem. see below. #!perl6 use v6; my $s; my $e; my $n; my $d; my $m; my $o; my $r; my $y; $s = any(0..10) none(0); $e = any(0..10); $n = any(0..10); $d = any(0..10); $m = any(0..10) none(0); $o = any(0..10); $r = any(0..10); $n = any(0..10); $y = any(0..10); I think these should be any(0..9). Indeed they should. I will assume they are written as such in my discussion below. my $send := construct($s,$e,$n,$d); my $more := construct($m,$o,$r,$e); my $money := construct($m,$o,$n,$e,$y); if ($send + $more == $money) { say send = $send; say +more = $more; say - say money = $money; } sub foldl(Code op, Any $initial, [EMAIL PROTECTED]) returns Any { if ([EMAIL PROTECTED] == 0) { return $initial; } else { return op(shift @values, ?SUB(op, $initial, @values)); } } sub add(Int $x, Int $y) returns Int { return $x + $y; } sub construct([EMAIL PROTECTED]) returns Junction { return foldl( sub ($x, $y) { $x * 10 + $y}, 0, @values); } How would the if (...) {...} work if there were more than one possible match to this equation? As written, this generates a rather large number of solutions. I do not see any test to make sure that the individual letters are different. Nor is there any check to see if all the e's assume the same value. So what you reach the: if ($send + $more == $money) {...} stage is $send being something equivalent to any(..) none(..0999), only no where near as simplified. Similar values can be found in $more and $money. Therefore, you're asking something like: Are there any two numbers between 1000 and that together total between 1..9? The answer is yes, and then you get an error as you attempt to print a raw junction, if you're lucky, or 9000 send lines, followed by 9000 more lines, followed by 9 money lines. Junctions are _not_ the same as unbound variables in Prolog. They do not widdle away inconsistent values as those inconsistencies are found. Most of them (all except all()) do not have to use the same value each time they are evaluated. If I'm wrong about this interpretation of this code, I apologize. But it certainly fits my understanding of junctions, which has grown by leaps and bounds over the last few weeks. HTH, -- Rod Adams
Re: Sets vs Junctions
Jonathan Lang [EMAIL PROTECTED] wrote: There are a couple of problems: first, a hash's keys are limited to strings; a set ought to be able to handle a wider range of data types. Last time I checked, there was going to be a way to declare a different data type for the key (which could easily be Any). -- Brent 'Dax' Royal-Gordon [EMAIL PROTECTED] Perl and Parrot hacker I used to have a life, but I liked mail-reading so much better.
Re: Sets vs Junctions
On Mon, Feb 21, 2005 at 10:32:15PM -0800, Jonathan Lang wrote: : ...then you've got the notion of Fuzzy Logic Sets, where the key would be : the prospective element and the value would be the degree of membership. : For fuzzy sets, hashes seem to be a better fit than junctions, which have : no obvious means of supplying the degree-of-membership info. You're still : stuck with the keys must be strings problem, so it's not an ideal : solution; but it's better than nothing. Hash keys are only strings by default. Just as any array can have a shape, so can any hash, and the shape of the hash is determined by the subtypes of its dimensional indices. (See S9 for more on this.) But using values for degree of membership is an interesting idea. On the other hand, if we ever have numeric datatypes with built-in error bars, those could generalize to keys with an associated certainty of some sort, and then you can leave the values out of it. In which case a junction might have varying degrees of likelihood varying between noneness and allness. It's all too powerful for a Pooh like me, though... :-) Larry