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)
Me no follow. Please use smaller words? -- Jonathan "Dataweaver" Lang
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' --> »cmp« <-- --> (-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
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 $x<3 ..." 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: binding arguments
Ingo Blechschmidt skribis 2006-01-05 18:32 (+0100): > Juerd wrote: > > Ingo Blechschmidt skribis 2005-12-25 17:37 (+0100): > >> I disagree about binding only being a language thing: > > I fail to see how your example code illustrates your disagreement. > >> return 42 > >> if (my $short := $long_parameter_name) == $specialcase; > I inferred that you think/thought that binding should/can't be used in > expressions No, that's not what I meant. A "language thing" means it's mostly relevant for the way you write something as a result of the feature. In case of binding, the most used application is aliasing: getting a second way to address the same variable -- probably because the alias is less typing. > >> push @foo, (my $head := pop @grtz); > > A bit better style, but I'd still recommend against it. > Consider: > my @sites = < abc.org def.org ghi.org >; > loop { > push @sites, (my $site := shift @sites); > check_for_updates($sites); > sleep ...; > } my $site := shift @sites; push @sites, $site; check_for_updates($sites); Although in Perl 6 I'd be much tempted to do: given shift @sites { push @sites, $_; check_for_updates($_); } Because $_ is visually easy to recognise, making it immediately obvious that it's the same thing in both lines. (This is also my main argument against any style that ALWAYS provides an explicit loop variable: $_ is easy to spot, and thus is more than just easy to type.) > Consider a perhaps more usual example: > while(...) { > process($tasks[$i++]); > if(...) { $i-- } # redo the last task > if(...) { $i = 0 } # redo all tasks > if(...) { $i++ } # skip next task > } As ugly. In fact, using an index is the ugliest part of your example. Still, separately, $i++ in the process() instruction is bad style IMO. Incrementing $i is important for program flow, and should be its own statement, directly following indentation. Also, if you remove process() here, the entire program is broken, because there was an important but easy to overlook subexpression was in it. Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
Re: binding arguments
Hi, Juerd wrote: > Ingo Blechschmidt skribis 2005-12-25 17:37 (+0100): >> I disagree about binding only being a language thing: > > I fail to see how your example code illustrates your disagreement. > >> return 42 >> if (my $short := $long_parameter_name) == $specialcase; I inferred that you think/thought that binding should/can't be used in expressions: Juerd wrote: > That works very well, because binding as an expression makes no sense > anyway, it being a language thing. Thus I wanted to demonstrate that "binding as an expression" does make sense (to me at least). Sorry if I misinterpreted your post. >> push @foo, (my $head := pop @grtz); > > A bit better style, but I'd still recommend against it. Consider: my @sites = < abc.org def.org ghi.org >; loop { push @sites, (my $site := shift @sites); check_for_updates($sites); sleep ...; } > You're doing something in an expression that has no effect on what > happens in the expression itself. Right; but I don't consider this as bad style or as "problematic". Consider a perhaps more usual example: # Perl 5 while(...) { process($tasks[$i++]); # The "++" does not have an effect on the expression itself, # writing "process($tasks[$i])" wouldn't make any difference. if(...) { $i-- } # redo the last task if(...) { $i = 0 } # redo all tasks if(...) { $i++ } # skip next task } --Ingo
Re: binding arguments
Ingo Blechschmidt skribis 2005-12-25 17:37 (+0100): > I disagree about binding only being a language thing: I fail to see how your example code illustrates your disagreement. > return 42 > if (my $short := $long_parameter_name) == $specialcase; That's terribly horrible style! > push @foo, (my $head := pop @grtz); A bit better style, but I'd still recommend against it. > (Unless of course, you consider this to be obfuscation.) Not obfuscation, but horrible style. You're doing something in an expression that has no effect on what happens in the expression itself. ($bar = $foo) =~ s/// is useful because you need a copy, and the inline copying is a clear indication of $bar's function: to be $foo in its state after s///. The same thing with := instead of = would be horrible, because $bar and $foo would be the same thing, during and after the expression, and the aliasing itself had nothing to do with the substitution. Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
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 <[EMAIL PROTECTED]> wrote: > 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. 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. And, if I can't put them in a <=, then Perl should complain very loudly, just as if I put something else that shouldn't be put into <=, like a Person object. If I call min() or min2() with a Person object and an array, I should expect loud complaints from the runtime. If a junction cannot behave itself in a numeric comparison, then similar complaints should be made. Rob
Re: Junctions again (was Re: binding arguments)
Luke Palmer wrote: > 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". Hmm... min2 behaves differently from min because the > function doesn't act as the negation of the <= function when dealing with junctions. As you say, wacky stuff. > 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. If junctions say that they're totally ordered by virtue of being usable in the <= function, and junctions shouldn't say that they're totally ordered, it follows that they shouldn't be usable in the <= function. Since one of the main purposes of junctions is to be usable in the <= function, this constitutes a problem. IMHO, the fallacy is the claim that something is totally ordered simply by being allowed arguments to the <= function. Total ordering is achieved by being allowed arguments to a <=> function that always returns one of -1, 0, or +1. When a junction is fed into a <=> function, it will not always return one of -1, 0, or +1; it could instead return a junction of -1's, 0's, and/or +1's (or maybe it should fail?). > 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*. I'm not following; could you give an example? -- Jonathan "Dataweaver" Lang
Re: Junctions again (was Re: binding arguments)
HaloO, Luke Palmer wrote: But junctions are so "special", that this abstraction wouldn't work. Well my point is that I dought that it is tractible for the compiler to come up with the dwimmery to pull the invocation of .values on the return value out of toomany and leave the cardinality check in, depending on the input beeing a junction or not. That is to re-write the junctive case to: sub toomany($j) { if $j > 4 { die "Too many values" } return $j; } my ($j,$k,$l) = map { toomany(get_junction().values) } ^3; Sort of a junctive compile :) My syntactical idea is that this might work if you naively write it without explicit .value and a junction numerifying to its cardinality. To get the junctive behaviour to trigger as you outline would be sub toomany(&j) # or perhaps even *&j { if j > 4 { die "Too many values" } return &j; } while an &j.values in the if still keeps the junction untriggered. Then an uncertain j.values might result in the compile time warning "return value of j not necessarily a junction". The only remaining thing for @Larry is to define an exclusive set of methods for querying junctions. Sort of like the "handle with care" stickers on containers! 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. Could it be that you think about it the wrong way around? I mean the values should be in the object grammar slot: "..., so a junction using *them* 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. Neither are they in the presence of references min(\3,{\3}) === min2({\3},\3) when the outer non-closure refs are created and optimized away by the compiler and the inner ones later depending on the order in which === evaluates its args. I mean that it sees 3 === \3 and returns false. Well, or I don't understand === ;) 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 control is outside. Junctions help people to obfuscate things like if min2(1,0) && min2(0,1) {die} where the inputs to && are returned from different spots in min2. 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. Junctions aren't ordered totally of course. But neither are they arguments to <=. The reverse is true: <= is an argument to the junction. And my point originally was about inventing a pleasing syntax that highlights this fact. E.g. the Complex type might support <= such that it returns true in case of equality and undef otherwise. The latter might lead people to regard it as false and hopefully cross-check with > and then draw the right conclusion after receiving another undef and promoting it to false. Namely that the net effect was a negated equality check! A gray view of a picture emerges from a blurred array of black and white pixels, and it takes more than two primal constituents for a color picture to emerge, e.g. black, white and fast motion with the right patterns deceive the human eye into perceiving color! Or think of contexts where 5 is not considered prime! Is it always? If not, in which context? The real objective of a type system is to quench undefinedness out of the essential parts of a program. 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! The thing that haunts me is that junctions make only sense if they bubble up into the control heaven so far that to achieve invariance a *complete* program has to be run for all conceivable permutations of pathes through the call graph! Might be nice for testing if given enough time, though :) 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
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)
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)
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)
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/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
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)
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)
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
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: binding arguments
Hi, Juerd wrote: > The next thing I thought was: hey, argument *passing* is actually > *binding* to variables in the sub, so why not use the := operator? > That works very well, because binding as an expression makes no sense > anyway, it being a language thing. And luckily, named arguments are > also a language thing, so that works out: I disagree about binding only being a language thing: # Happened to me in Perl 5 today sub foo ($long_parameter_name) { return 42 if (my $short := $long_parameter_name) == $specialcase; ...usual processing with $short... } push @foo, (my $head := pop @grtz); (my $alias := $long_name).grtz(); # etc. (Unless of course, you consider this to be obfuscation.) --Ingo
Re: binding arguments
On 12/25/05, Juerd <[EMAIL PROTECTED]> wrote: > foo( > named_arg := $value, > other_arg := $value, > ); I'll point out that Joe's argument is completely moot, because you're not using $s on the named arguments. As a matter of fact, we could double up the := symbol as both binding and named arg passing, using a =>-like heuristic (\w-only means it's a named arg). That kind of symbol overloading might be too confusing (but as you point out, no more confusing than the pair syntax). > Using := for this also fixes the problem of having to use *, which feels > like a hack, to use a single stored named argument: > > sub f ($foo) { ... } > > my $a = foo := $bar; # named argument > my $b = foo => $bar; # pair > > f($a); # f($bar); Okay, it seems like I have to argue this every time it comes up. In my "demagicalizing pairs" proposal, the * was by linguistic design, not a way to get around a problem that the proposal had. One might even say that it was the main reason for the proposal. 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] Let's say you're tossing around a list of these "named argument" objects, constructing it for a call to a function with a very complicated interface. You see: sub sort_nameds([EMAIL PROTECTED]) { return () unless @nameds; my $pivot = shift @nameds; my @pre = grep { .name lt $pivot.name || .name eq $pivot.name && .value < $pivot.value } @nameds; my @post = grep { .name ge $pivot.name && (.name ne $pivot.name || .value >= $pivot.value) } @nameds; return (sort_nameds(@pre), $pivot, sort_nameds(@post)) } And you say, hmm, interesting, there is some code duplication there. So you refactor: sub sort_nameds([EMAIL PROTECTED]) { my sub cmper($x, $y) { $x.name lt $y.name || $x.name eq $y.name && $x.value < $y.value } return () unless @nameds; my $pivot = shift @nameds; my @pre = grep { cmper($_, $pivot) } @nameds; my @post = grep { !cmper($_, $pivot) } @nameds; return (sort_nameds(@pre), $x, sort_nameds(@post)); } But there is an error there. You can't pass $pivot (or $_) into cmper inside those greps, because they will try to bind to the named arguments of cmper, instead of passing proper as you'd like them to. You might say "okay, we'll just invent a syntax that says 'pass these as objects, not as named args'". Maybe \$arg or whatever. Now you have to know what's in your variables to abstract them properly. This is pretty much the opposite of the idea of polymorphism, which says "I can do something to what you give me, no matter what it is". And we all know by now, hopefully, that once you're beyond scripting, polymorphism is a good thing. Convenient, natural syntax is good, but it must not hinder our ability to abstract. You've got to tell the compiler when you're passing a named argument. The * syntax to pass a pair was very intentionally *not* a hack. As far as the rest of the proposal goes... The ideas of pairs and named arguments have been separate ever since we demagicalized them; we've just overloaded their syntax. What you propose gives each its own syntax, but instead overloads the syntax of binding to named arguments (which is indeed conceptually closer). But you lose something important in the process: The :foo($bar) syntax. I, for one, like writing my named arguments with that style more than I do with the => style. So I'd be happy if you stole :foo($bar) for named args and left only => for pairs, but that might make people who write hashes with :foo($bar) pairs unhappy. All in all, I think the syntax overloading here is a pretty fair compromise. Maybe it would make you feel less uneasy if you thought of it as syntactic overloading rather than a special interpretation of pairs. [1] This is one of my quibbles with junctions, too. Luke
Re: binding arguments
Joe Gottman skribis 2005-12-24 19:59 (-0500): > sub foo($named_arg) {say $named_arg;} > my $named_arg = 1; > my $value = 2; > foo($named_arg := $value); #Does this bind my $named_arg to $value? Because the := is used in .(), it is not binding in the current scope, but in the called subroutine. In foo($bar := $baz), $bar is always the name of the argument, and if "foo" doesn't have that name, and doesn't have anything to slurp unknown named arguments, things fail. > To avoid this, perhaps we can use <- or -> instead? The problem about this is that it has to be exactly the other way around than pairs, which may make the difference a bit too large. Besides that, it is a big problem for people who don't like to use whitespace: foo < -5, they write as foo<-5. I do not think there is any need to have different symbols for direct binding and named argument binding, because I can't think of any case where using direct binding in an expression has any benefit. Copying in expressions is usually done because the copy is modified, but that argument doesn't work for aliasing. However, := is a weird symbol, the more I think about it. It has nothing to do with colons or assignment. Colons are used for pairs, assignment for copying values. It looks like +=, but doesn't quite work like it. And ::= seems entirely arbitrarily chosen. But I may be wrong. Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
RE: binding arguments
> -Original Message- > From: Juerd [mailto:[EMAIL PROTECTED] > Sent: Saturday, December 24, 2005 7:26 PM > To: perl6-language@perl.org > Subject: binding arguments > > Merry Christmas to you all! > > We use => for pairs, but also for something very different: named > argument binding. Yes, pairs are used for that, but that introduces > problems. The most important problem, that pairs sometimes have to be > passed, and sometimes have to be named arguments, is fixed with a hack > that to me, just doesn't feel right: if the pair is literal and not > inside grouping parens, it's a named argument. Otherwise, it's a pair. > Especially with the function of the () glyphs being different between > with and without whitespace after the subname, this can be very > confusing. > > I'd like pairs and argument binding to be two different things. With > different syntaxes. > > The next thing I thought was: hey, argument *passing* is actually > *binding* to variables in the sub, so why not use the := operator? That > works very well, because binding as an expression makes no sense anyway, > it being a language thing. And luckily, named arguments are also a > language thing, so that works out: > > foo( > named_arg := $value, > other_arg := $value, > ); > The only problem I'd have with this is what if there already exists a variable with the same name as the named argument? sub foo($named_arg) {say $named_arg;} my $named_arg = 1; my $value = 2; foo($named_arg := $value); #Does this bind my $named_arg to $value? say $named_arg; #Must print 1, not 2 To avoid this, perhaps we can use <- or -> instead? foo($named_arg <- $value); foo($value -> $named_arg); Which one of these two is better depends on whether you think the parameter or the argument being bound to it is more important. Joe Gottman