Re: Hackathon notes
Yuval Kogman wrote: Rob Kinyon had a strong argument (in #perl6) that anything that depends on load order is bound to make someone's head hurt. He has a point. Especially if one in working in something like mod_perl, and the order various modules were actually loaded in can vary greatly from the order they are listed in the source code. Unless we have every lexical scope keep track of what order *it* thinks all the MMD methods *should* have been loaded in, which overall feels very painful. I thought I've had is whether there should be a "subname" that can be defined on a given multi, to identify it as distinct from the others, and not having to type the full signature. Something analougous to HTTP/HTML # suffixes. One could then use that subname in conjuction with the short name to refer to a specific method. This could then let a user easily skip MMD when DWIMmery fails. To be useful, it would need to be simple syntax. I'll propose forcing "# as comment" to be "\s+# as comment" (if it isn't already), and have subnames specified as shortname#subname. multi method foo#bar (Num x) {...} multi method foo#fiz (String x) {...} $y = 42; $obj.foo#fiz($y); # even though $y looks like a Num $obj.foo($z); # let MMD sort it out. It's unclear if $obj.foo($y); even works, or should work, even if it does. It be no means solves all of Yuval's problems, but it would be a handy workaround to un-multi your calls. -- Rod Adams
Re: MMD handling (was Re: Hackathon notes)
David Storrs wrote: On Jul 8, 2005, at 4:25 PM, Dave Whipp wrote: Rod Adams wrote: multi method foo#bar (Num x) {...} multi method foo#fiz (String x) {...} $y = 42; $obj.foo#fiz($y); # even though $y looks like a Num $obj.foo($z); # let MMD sort it out. Instead of changing the parse rules for #, why not just use a trait? multi method foo is short_name('bar') {...} I thought about that, but then thought that to become commonplace it was a bit much to type. I also couldn't come up with a way to call a given multi that matches on a given attribute, without adding even more complexity to MMD. Having additional tags might also give us something to hang priority traits off: "foo#bar is more_specific_than(foo#baz);" might influence the order of clauses in the implicit given/when block. It feels like there should be a generalization of operator precidence here (even thought he two are superficially dis-similar, the looser/tighter concept appears valid). Although I like the idea of reusing this concept, I'm not sure that it really solves the problem. Fundamentally, we're trying to make MMD behave intuitively with no programmer effort. Well, if one views MMD as "a list of methods to try, each with it's own requirements on it's arguments", then it can completely solve the problem, along with a method sort function. 1) take all methods the user specified "higher than/lower than/equal to" out of the mix. 2) sort remaining methods via a standardized function. 3) put all the ones taken out in step 1 back in, where they are requested. 4) scan the methods, in order, for the first that accepts the given arguments. 5) dispatch to the chosen one in #4 -or- 6) begin AUTOMETHing, etc. Then all we need is a DWIMish sort function. Some ideas: -- longer parameter lists go before shorter ones. -- if param(n) of one ISA param(n) of another, it goes first. -- slurpies after non-slurpies -- a hashkey of the parameter types (for deterministic coin flips) I'm not committed to what goes into the method sort function, or in what order, just the concept of it. To me it seems easier to visualize than distances, etc. If nothing else, it should be easy to explain to users and programmers. With the name tagging idea from before, one could then say things like: multi sub foo#lastresort ([EMAIL PROTECTED]) is after(foo#default) {...} for when the default sort does things incorrectly. A reasonable extensions of this would be to have a coderef attribute that determines if a supplied set of arguments is acceptable, rather than the default check. This is a possible MTOWTDI for the 'where' clauses. Then again, there are likely several glaring problems with this idea that I'm just not seeing at the moment. -- Rod Adams
Re: Perl 6's for() signature
At 10:05 AM 7/31/2003 -0600, Luke Palmer wrote: Well, I don't think it's possible, actually. There's a flattening list context at the beginning (implying a sugary drink from 7 eleven), followed by a code block. But, as we know, slurpy arrays can only come at the end of positional parameters. Anyone but me feel the need for non-greedy slurpy arrays? similar to non-greedy RE matches? Then we could do: sub for ([EMAIL PROTECTED], &block) {...} Proposed behavior of *?@ : All Arguement to Parameter mapping left of it are processed Left to Right. Once seen, the mapping starts over right to left. Everything remaining is slurpable. Yes, it's more expensive to use, just like the RE version, but shouldn't impact performance _too_ bad when it's not, since the behavior will be detectable at compile time. Thoughts?
RE: Perl 6's for() signature
At 01:29 PM 7/31/2003 -0400, Hanson, Rob wrote: > Anyone but me feel the need for non-greedy > slurpy arrays? similar to non-greedy RE matches? I definately like the idea of having something like that. It probably wouldn't be used much, but it is nice to have the option. One thing though, can't you accomplish the same thing by slurping everything, then poping the block off of the array? One could do most of the stuff in P6 parameters with P5's @_. But as Damian showed at the end of E6, it can quickly grow to a nightmare, and making it nicer is what P6 is all about. -- Rod Rob -Original Message- From: Rod Adams [mailto:[EMAIL PROTECTED] Sent: Thursday, July 31, 2003 12:56 PM To: Perl 6 Language Subject: Re: Perl 6's for() signature At 10:05 AM 7/31/2003 -0600, Luke Palmer wrote: >Well, I don't think it's possible, actually. There's a flattening >list context at the beginning (implying a sugary drink from 7 eleven), >followed by a code block. But, as we know, slurpy arrays can only >come at the end of positional parameters. Anyone but me feel the need for non-greedy slurpy arrays? similar to non-greedy RE matches? Then we could do: sub for ([EMAIL PROTECTED], &block) {...} Proposed behavior of *?@ : All Arguement to Parameter mapping left of it are processed Left to Right. Once seen, the mapping starts over right to left. Everything remaining is slurpable. Yes, it's more expensive to use, just like the RE version, but shouldn't impact performance _too_ bad when it's not, since the behavior will be detectable at compile time. Thoughts?
What to do....
So I've been lingering around p6-language for a few months now, and have noticed the following two trends: 1) All of the work forward on p6 design seems to come from either Larry or Damian. (If there are others working in the shadows back there, please make yourselves heard.) Most, if not all, the discussions of recent has been of the form "How does work in relation to mentioned in ?". While meaningful and worthwhile topics all, they do not drive the language forward terribly fast. 2) Reality is constantly interrupting Larry and Damian's efforts in rather nasty ways. Taken separately, either of these trends are bothersome. Taken together, this feels like a problem. So the next question is, is there anything that can be done to improve matters? I'm moderately certain that everyone wishes they could do something about #2, I'm moderately sure that the p6 community has done as much as they can on that account. So my real question is, is there any way for the community to get together and help take some of the load off these two in the design, or is the current process the Best We Can Do (tm) and we just need to practice that most unvirtuous of things "patience"? Can apocalypses be something more along the line of scratches on the wall, that then go through some level of deciphering or translation into something closer to English? Are there topics that need brainstorming that this list could take over? I certainly don't want the language to loose the internal cohesiveness that all languages need, and am suitably scared of "design by committee"... but I'd like to think that there's something that could be done to help matters. Comments? Suggestions? -- Rod Adams PS -- I'm willing to commit several hrs a week to the effort.
Re: What to do....
At 10:40 PM 11/14/2003 -0800, chromatic wrote: I'd really like to see people start turning the existing design documents into story cards and programmer tests for Perl 6. That'll make it much easier to implement the thing. So basically go back through the existing Apoc/Exeg's and break it down into a long list of features. Then start building tests for each feature. I'll give this some thought. Design decisions have to be broken into individual tasks at some point. Sure, some of them will change as we go along. There's enough there that can be implemented now, though, without waiting for the big thud of specifications. There's plenty of useful work to go around. Running test cases are *much* easier to implement against than anything else. (Hey, it's been working fairly well on the Perl XP Training Wiki: http://xptrain.perl-cw.com/). -- c
Re: The C Comma
At 04:40 PM 11/24/2003 -0800, Michael G Schwern wrote: I definately agree that this is used rarely enough that it should be a word and not a single character. "then" sounds too much like "if/then" which is confusing. Its exactly the opposite from what you're trying to convey. It also doesn't convey anything about "evaluate the left hand side, ignore the results and evaluate the right". Unfortunately, I don't have a better name. C Of course I've always thought the semicolon would have been a better choice for the "C comma". That way C<($a, $b, $c)> would always be a list, and C<($a; $b; $c)> would be $c, after $a and $b are evaled. I haven't thought out how much havoc this would cause the parser, but from this programmers view, it seems pretty intuitive. -- Rod
Re: [perl] Re: Object Order of Precedence (Was: Vocabulary)
Luke Palmer wrote: Joe Gottman writes: - Original Message - From: "Jonathan Lang" <[EMAIL PROTECTED]> To: <[EMAIL PROTECTED]> Sent: Saturday, December 20, 2003 3:41 PM Subject: [perl] Re: Object Order of Precedence (Was: Vocabulary) Larry Wall wrote: If DangerousPet doesn't define a feed method at all, then we might dispatch to Pet and Predator as if their methods had an implicit "multi". And the C trait is the tie-breaker when several options are equally likely candidates (in terms of type information); OK. I'm a little leery about calling this trait "default". The problem is that we are already using "default" as a keyword (see the switch statement), and having a trait with the same name as a keyword might confuse users and/or the compiler. Perl's using a top-down compiler now, so it won't be looking for the keyword variant of C after "is". "default" is sufficiently overloaded in English, and by context in Perl, that I don't think anyone will get confused. Not to say that other names for this trait aren't welcome. C
Re: Perl 6 using Perl 5 modules
PerlDiscuss - Perl Newsgroups and mailing lists wrote: When the official release of Perl 6 is released and I start to write some Perl 6 programs using Perl 5 modules, will I get any errors? How will this be handled? Will all of the Perl 5 modules have to be ported over and converted to Perl 6 code? Can I have a basic perl6.pl file while using the standard perl 5 IO::Socket module or whatehaveyou? My understanding of things is that this is what Ponie is all about. Make it where Parrot can handle P5 code. Of course, when P6 is released, Parrot will it. Since one of the Parrot ideals is the interoperability of code from various sources, the answer to your question is yes (as long as Ponie supports it). Try the Ponie FAQ: http://opensource.fotango.com/software/ponie/faq --Rod
Re: Semantics of vector operations
Luke Palmer wrote: Austin Hastings writes: I think you guys may be talking at cross purposes. Robin, I think, is talking primarily about coding, while Damian talks of reading. Perhaps Damian's solution is a Unicode2Ascii perl script that emits formal names, combined with the implementation in Perl of the E alternative spellings. OTOH, Robin's concern for how to code when you're stuck with 7 bit ascii on the boot console of a Sun box remains valid, and *I* sure would rather have a short name available in a standard way. Perhaps this is where the "accept Unicode and HTML" philosopy comes in, sort of like the reverse of C< use English; >, to wit: use asciiops; ... @list.Emethod; # Instead of E I think that using the POD entities + Unicode is fine, but the solution to giving people who use E often, I belive, is to be able to define these escapes simply. Either the module writer or the user would map a more usable escape to that character. Luke Question in all this: What does one do when they have to _debug_ some code that was written with these lovely Unicode ops, all while stuck in an ASCII world? Also, isn't it a pain to type all these characters when they are not on your keyboard? As a predominately Win2k/XP user in the US, I see all these glyphs just fine,but having to remember Alt+0171 for a  is going to get old fast... I much sooner go ahead and write E and be done with it. Thoughts? -- Rod
Re: Unicode under Windows (was RE: Semantics of vector operations)
Austin Hastings wrote: From: Rod Adams [mailto:[EMAIL PROTECTED] Question in all this: What does one do when they have to _debug_ some code that was written with these lovely Unicode ops, all while stuck in an ASCII world? That's why I suggested a standard script for Unicode2Ascii be shipped with the distro. Good Idea, which would also beg an ASCII2Unicode script to reverse the process. Also, isn't it a pain to type all these characters when they are not on your keyboard? As a predominately Win2k/XP user in the US, I see all these glyphs just fine, but having to remember Alt+0171 for a  is going to get old fast... I much sooner go ahead and write E and be done with it. Thoughts? This has been discussed a bunch of times, but for Windows users the very best thing in the US is to change your Start > Settings Control Panel > Keyboard > Input Locales so that you have the option of switching over to a "United States-International" IME. Once you've got that available (I used the Left-Alt+Shift hotkey) you can make a map of the keys. The only significant drawback is the behavior of the quote character, since it is used to encode accent marks. It takes getting used to the quote+space behavior, or defining a macro key (hint, hint). (Links Snipped) Thanks for the pointers. I've now set up Win2k so I can easily switch between US and United States International. Works nicely. Now I have to go beat up the Thunderbird guys for trapping the keyboard directly and not allowing me to type the chars here. Thanks Again -- Rod
Re: The Sort Problem (was: well, The Sort Problem)
Here's my stab at a sort syntax, pulling syntax over from REs: @out <== sort key:ri($_->[2]), key:s($_->[4]) <== @in; Basicly, you have a list of RE syntax like C values, whilch take various modifiers to say how to play with that key, and then an expr on how to generate the key given element $_. Possible modifiers: (verbose versions welcome) :rreverse/descending :n force numeric comparisons :s force string comparisons (default) :u unicode (implies :s) :i case insensitive (implies :s) :l localized collation order :x call custom compare sub (a la P5) This allows: @out = sort keys %hash; # everything gets defaulted @out = sort key:x{myfunc($a) cmp myfunc($b)}(), @in; # handy for P5 migration, but not much else @out = sort key(myfunc($_)), @in; # same as above, but much better. @out = sort key(%lookup{$_->{remotekey}}), key:ir($_->{priority}), @in; # complex in P5, easy here. Advantages: - Uses syntax idioms used elsewhere in P6. - Common cases are easy - Decent huffman coding. Disadvantages: - Do we really want things that look like REs that are not REs? - If we do this, are we setting ourselves up to create other RE-like creatures for grep, for, etc, to the point where people will start wanting to roll their own in modules? Thoughts? -- Rod
Re: The Sort Problem
Austin Hastings wrote: Off the top of my head, I can't think of a case where the compare sub would be needed unless the key was not well-ordered. Does anyone have an example of a case where the key-extraction sub approach doesn't reduce the problem to a Scalar comparison? I can't find the P5 code I used for it right off, but I remember a case when I was playing around with various football (US) stats. I was ranking teams, and had something akin to: @teams = sort {$b->{WinPct} <=> $a->{WinPct} || ($a->{Conference} eq $b->{Conference} ?($b->{ConfWinPct} <=> $a->{ConfWinPct} || $b->{ConfWon}<=> $a->{ConfWon} || $a->{ConfLost} <=> $b->{ConfLost}) :($a->{Division} eq $b->{Division} ?($b->{DivWinPct} <=> $a->{DivWinPct} || $b->{DivWon}<=> $a->{DivWon} || $a->{DivLost} <=> $b->{DivLost}) :0 ) ) || $b->{Won} <=> $a->{Won} || $a->{Lost}<=> $b->{Lost} || $b->{GamesPlayed} <=> $a->{GamesPlayed} } @teams; Creating a keycode for this situation is not a trivial task at all. So sorts do occur in the real world for which there is no straightforward way to generate a sortkey. Albeit considerably rare. Also, I think there is utility in have a compare sub supported so that: 1) porting P5 code is easier. (a minor design rationale, but it exists) 2) people used to thinking in terms of compare subs (from C, P5, and points of the programming universe) can still think that way. 3) most importantly to me, so that There's More Than One Way to Do It. -- Rod Adams
Re: The Sort Problem
Damian Conway wrote: Uri persisted: > but int is needed otherwise? int is more commonly a sort key than float. > it just feels asymetrical with one having a symbol and the other a named > operator. Sorry, but that's the way the language works. The more general and usual conversion (to number, not to integer) has the shorter name. For the record, I do a lot of statistical work. On the sorts where I care about speed, I'm using floats far more often than ints. Uri's usage obviously varies from mine. Let's not hack up the language to make sort more efficient for some arguable benefit. I would entertain, however, C and C comparators (and functions in core) that pretty much (if not precisely) alias C<+> and C<~>, forcing said type. > DC> If you don't explicitly cast either way, C just DWIMs by > DC> looking at the actual type of the keys returned by the extractor. > DC> If any of them isn't a number, it defaults to C. > > that doesn't work for me. the GRT can't scan all keys before it decides > on what comparison operator is needed. the GRT needs to merge keys as > they are extracted and it needs to do the correct conversion to a byte > string then and not later. you can't DWIM this away if you want the > optimization. EXACTLY!!! So, if you want the GRT to kick in, you have to make sure the return type of your block is appropriate. If you don't give the compiler that hint, you don't get the optimized sorting. When fed a number that it doesn't trust to be an int or a float, couldn't the GRT store the number with C? (ok, there's some prepping for sign and endian, but you get the point) Seems like a not-terrible way to handle the issue. Here's another example (all praise be to Rod!): @teams = sort [ # 1 parameter so it's a key extractor... {+ $^team->{WinPct} }, # 2 parameters so it's a comparator... { ($^a->{Conference} eq $^b->{Conference} ? ($^b->{ConfWinPct} <=> $^a->{ConfWinPct} || $^b->{ConfWon}<=> $^a->{ConfWon}|| $^a->{ConfLost} <=> $^b->{ConfLost}) : ($^a->{Division} eq $^b->{Division} ? ($^b->{DivWinPct} <=> $^a->{DivWinPct} || $^b->{DivWon}<=> $^a->{DivWon}|| $^a->{DivLost} <=> $^b->{DivLost}) : 0 ) }, # 1 parameter each so all three are key extractors... {+ $^team->{Won} } is descending, {+ $^team->{Lost} }, {+ $^team->{GamesPlayed} } is descending, ] @teams; Now that's just spiffy. Except in moving from my P5 version to your P6 version, you have to s/?/??/ and s/:/::/, IIRC. > DC> But you *can't* apply C to a Code reference. > then how did you apply 'is insensitive'? I applied it to the *block* (i.e. a closure definition). That's not the same thing as a Code reference. > what i am saying is i think that you need to go back to the drawing > board to find a clean syntax to mark those flags. No, I think we have it...just put the appropriate trait on the extractor *block* when you define it. I really don't see the problem with @out = sort {lc $_}, @in; It's short, simple, unambiguous, IMO very clean. But if people want to take a tool that we're creating anyways elsewhere in the language (traits) to provide another way to do it, that's fine too. > i just don't like the reverse args concept at all. it is not > semantically useful to sorting. sorts care about ascending and > descending, not a vs b in args. The problem is that sometimes comparator logic is suffiently complex that a single comparator needs to have a "bit each way", as in Rod's football team comparator above. What my football example was meant to show is that no matter how much we abuse poor C in the name of progress, we need to have a way to drop it all and go back to how we did it in P5, for those truly pathological cases where nothing else works. If people don't trust this, I'll come up with something worse. As a side note, the reason I couldn't find the original sort in question is that I later scraped it in favor of a more robust 100 line sub to figure out who ranked where. But in more common case, how much it break things to have type Comparator ::= Code(Any, Any) returns Int; become type Comparator ::= Code(Any, Any) returns Int | '!' Code(Any, Any) returns Int; where the '!'
Re: Exegesis 7: Fill Justification
Damian Conway wrote: Richard Nuttall suggested: An alternative is to have "fill rightmost gaps" and "fill leftmost gaps" on alternate lines. This produces more balanced looking columns, so they don't all look heavier on the left. That's a *very* interesting idea. What do people think? The Version 1 samples had various "whitespace worms" appear over on the right, which get broken up to some extent with v2. However, v2 has some minor even/odd patterns that get some mild notice. But overall, I like #2 better. Since I don't think whitespace management is something that needs to be deterministic, why not choose the gaps randomly? If we do need deterministic results, then a pseudo-random pattern where you expand the C<(($LineNumber * $GapToExpandCounter * $SomePrimeNumber) % $GapsOnLine)>th gap? There's also a gremlin in the back of my head telling me the typesetting industry probably solved this riddle years ago. But I have no time to research it this week. -- Rod
Re: Compile-time undefined sub detection
Larry Wall wrote: On Fri, Mar 05, 2004 at 06:45:58PM -, Rafael Garcia-Suarez wrote: : Of course :) the main problem is not that CHECK blocks are executed : late (just at the end of the compilation phase); it's that they're : executed too early, notably in some persistent environment, notably : mod_perl (or mod_parrot in the future.) When you have a virtual machine, : you'll end up including modules at run time, because the main : compilation phase becomes less important. Thus CHECK blocks become : worthless, code-reusability-wise. Possibly a CHECK block that is compiled after end of main compilation should translate itself to a UNITCHECK. But maybe it should be an error. But it's also possible that CHECK should mean "unit check", and there should be an explicit MAINCHECK for delegating checks to the main compilation. In that case, only in the main compilation would CHECK and MAINCHECK mean the same thing. (And since MAINCHECK is explicitly requesting a check at the end of main, a late MAINCHECK should probably be considered an error. (But by that argument, a late CHECK should probably fail under the current naming scheme.)) Anybody got opinions on the naming of these beasts? Certainly *not* renaming CHECK is more compatible with Perl 5. And I kinda got fond of UNITCHECK in the last hour or so. :-) Larry Given the fact that use of these blocks are overall quite rare, and potentially very confusing to the casual perl hacker who encounters one of them, I propose a rather different tact: BEGIN => EXECUTE_ON_PARSE CHECK => EXECUTE_AFTER_COMPILE and EXECUTE_AFTER_UNIT_COMPILE INIT => EXECUTE_INITIALIZATION END => EXECUTE_ON_EXIT This also has the advantage of being able to reserve all subs with name EXECUTE_.* for compiler/interpreter special sub like these, so we could add more of them come perl 6.8 w/o much issue. -- Rod
A12: Single Dispatch over Mult Dispatch
(Note: throughout this message, "method" refers to "sub"s and "submethods" as well.) I'm having trouble coming up with a solid argument for why Single Method Dispatch (SMD) is our default, when we have MMD. At this point, I'm tempted to slap a C in front of all my methods, for the sake of future extensibility. So my basic idea is to solicit reasons why we shouldn't make C the default, and then allow for c for the obscure cases where one wants such behavior. Arguments in favor: = If you've bothered to define a signature for the method, you expect things that call it to match that signature. I would expect an error when I tried to call a method with parameters that didn't match the signature. This change would move that error from "Call doesn't match signature" to a "Method for name(signature) not found". = If you haven't defined a signature, MMD will match against the implied signature, which it always should, so no problem. = Making everything multi makes extending existing code much easier, for obvious reasons. Arguement against: = Likely makes things harder on the optimizer. Or more likely, makes MMD optimization a lot more important. But that's a p6i problem, not a p6l one. Another way to interpret this post is "When is SMD preferred over MMD? And is that enough to make it the default?" If I'm missing something basic feel free to correct me. -- Rod Adams
Re: Compatibility with perl 5
Larry Wall wrote: In general it's probably a lousy idea to rely on #!/usr/bin/perl6 to select language since you want the version number to select the version of Parrot you're running, not the version of Perl. One thing that occurred to me over the weekend is that we could fix all the one-liners using a similar strategy to the package/module/class switch. It would be a (roughly) zero growth option to simply switch to :x syntax for command-line switches instead of -x syntax. Any program that uses colon switches instead of minus switches would then automatically be assumed to be in Perl 6. So maybe a minimal Perl 6 marker would be something like #!/usr/bin/perl : #!/usr/bin/perl :: #!/usr/bin/perl :6 Larry Uhm... What exactly is wrong with #!/usr/bin/perl -M6 ? -- Rod
Re: RFC eq and ==
Luke Palmer wrote: Admittedly, if you use == for everything, you can force string or numeric comparison this way: if +$a == +$b {...} # numeric if ~$a == ~$b {...} # string Hmm. In my head, I would expect == to have implicit numification on the operands (unless user-overloaded to something else, but that's different). In turn, I'd expect eq to have implicit stringifies. Therefore I'd expect the +'s to redundant in the first example. I'd then expect the second example to first convert $a and $b to strings because of the ~'s, then, because it sees the ==, it would numify those strings and do a numeric compare. Are my expectations misaligned here? -- Rod
Re: RFC eq and ==
Luke Palmer wrote: Oh, sorry, wasn't clear. That's *if* eq was eliminated and == became a polymorphic operator. You're correct in terms of the current (and hopefully continuing) state of things. Went back and re-read your first post, and that is indeed what you were saying, I just read it too fast. I'd be seriously annoyed if eq went away. It's one of those things that makes Perl Perl. It's up there with the postfix if. ~$a == ~$b feels too much like: Cast(String, $a).Compare(Cast(String, $b)) -- Rod
Re: FW: Periodic Table of the Operators
Smylers wrote: Gabriel Ebner writes: Joe Gottman wrote: The zip operator is now the Yen sign (¥). How are those without a US keyboard supposed to type this? On Windows you can probably press Alt Gr then type in some number. Close. AltGr-Minus. If you're using the US-International layout that ships w/ Windows. -- Rod
Re: FW: Periodic Table of the Operators
Jared Rhine wrote: I haven't yet seen an example presented where using a Unicode operator would save keystrokes, for instance. That depends entirely on how you plan to generate them. If you are relying on a special command in your editor of choice, yes, the ASCII equiv is fewer keystrokes. If, however, you remap your keyboard (easily doable in X and Win32, I'd assume Macs can as well), then the common Unicode characters are an AltGr away. Thus, « one shifted keystroke (AltGr-[), << is two shifted keystrokes (Shift-, Shift-,). -- Rod Adams
Slices
Come the glorious age of Perl6, will hash slices be enhanced to allow things like the following? [EMAIL PROTECTED]'expected'} = [EMAIL PROTECTED]; Specifically, having the slice be something other than the last element. This likely dictates having {} be able access a list of of hashrefs, not just a single hashref or hash. Comments?
Re: undo()?
Brent 'Dax' Royal-Gordon wrote: David Storrs wrote: Well, at least that's a nice simple explanation. Why couldn't anyone have explained it to me that way before? Unfortunately, it means that continuations are a lot less useful than I thought they were. :< Actually, I think you're underestimating the little guys. After all, if they rolled back *all* of your changes, all they could do was repeatedly execute the same code! Hmm... Could someone please give a few prototypical cases where continuations really shine over other methods of structure? A guess from my current understanding: You're wanting to play with a database. You take a continuation. You see if have a database handle open and good to go, if so you do your thing. (can you then dismiss the continuation? do uninvoked continuations pile up somewhere?). If the handle is not ready, you do everything needed to prepare the handle, and then invoke the continuation. But I don't see how a continuation gained you much over C. So what makes them so cool? -- Rod
Re: undo()?
Austin Hastings wrote: --- Rod Adams <[EMAIL PROTECTED]> wrote: A guess from my current understanding: You're wanting to play with a database. You take a continuation. You see if have a database handle open and good to go, if so you do your thing. (can you then dismiss the continuation? do uninvoked continuations pile up somewhere?). If the handle is not ready, you do everything needed to prepare the handle, and then invoke the continuation. But I don't see how a continuation gained you much over C. So what makes them so cool? You know how you can log in to your webmail/slashdot/sourceforge/amazon account, and get a cookie that says you're logged in? And you know how you can then go into your browser's history list and pick up some entry that was invalid, or came from yesterday, and when you click through, the cookie (local data) that says you're legitimately logged in stays with you, so the site doesn't give you a hard time? That's continuation-like behavior. Continuations will let you take "function pointers" at an arbitrary location: instead of entering the top of the function, you can come in to the middle. They are similar to setjmp/longjmp in this context: you have to pass through once to "take" the continuation, before you can invoke it. But you can invoke it arbitrarily many times, unlike set-/long-jmp, since the continuation closes over the entire call stack. =Austin Well, that's another explanation that jives with my understanding of them. But I still don't have an idea of when I would actually want to use them in something I'm writing. -- Rod
Re: Why do users need FileHandles?
Dave Whipp wrote: I was thinking about the discussions about the "open" function, and of the capabilities of "string"s. Given that we'll have things like $str.bytes, etc. It doesn't seem a stretch to suggest that we could also have $str.lines. Once we have that, and also a level of pervasive laziness (lazy evaluation), it seems to me that we don't really need user-visible file handles for most of the common operations on files. Imagine: my $text is TextFile("/tmp/foo.txt"); for $text.lines { ... } I guess what I'm saying is that if we can make tying the standard idiom, then we can relax you huffmanization worries for things like the "open" function. Uhm, my impression was that most of the "huffmanization" discussion was centered around declaring a file handle to be read only, write only, read-write, exclusive, etc. Masking the file handle with what basically amounts to a file handle subclass like you describe will still need to allow the user to specify all those attributes. So you would still need to allow: my $text is TextFile("/tmp/foo.txt" :rw ); my $text is TextFile("/tmp/foo.txt" :excl ); Not that having wrapper classes for file handles is a bad idea, it just doesn't relate to what I saw being discussed. Oh, and "TextFile" should be spelled "IO::File::Text", IMHO. -- Rod Adams
Re: Why do users need FileHandles?
Dave Whipp wrote: "Rod Adams" <[EMAIL PROTECTED]> wrote in message news:[EMAIL PROTECTED] Uhm, my impression was that most of the "huffmanization" discussion was centered around declaring a file handle to be read only, write only, read-write, exclusive, etc. Masking the file handle with what basically amounts to a file handle subclass like you describe will still need to allow the user to specify all those attributes. So you would still need to allow: my $text is TextFile("/tmp/foo.txt" :rw ); my $text is TextFile("/tmp/foo.txt" :excl ); my $text is TextFile("/tmp/foo") is rw; my $text is TextFile("/tmp/foo") is const; truncate Vs append would be infered from usage (assign => truncate). One might be able to infer read Vs write in a similar way -- open the file based on the first access; re-open it (behind the scenes) if we write it after reading it. Case 1: So I wanted to do a read/write scan, so I create my TextFile, start reading in data, so the file is opened for reading. Then, I come to the part where I want to update something, so I do a write command. Suddenly the file has to be closed, and then re-opened for read and write. And all my buffers, file pointers and the like are reset, (though curable with very careful planning), leaving me in a bad spot. Better if I could just declare the file open for read and write at open time. Case 2: I meant to use some critical data file in read-only mode, and accidently use a write command somewhere I didn't mean to, and silently just clobbered /etc/passwd. Better if I could have just opened the file read only, and trigger an error on the write command. What design philosophy would you envision TextFile taking to handle both these cases in a coherent fashion? :excl would probably need to be an option, but is not sufficiently common to be agressively huffmanised: my $text is TextFile("foo.txt", :no_overwrite); my $text is TextFile("foo.txt") does no_overwrite; ot that having wrapper classes for file handles is a bad idea, it just doesn't relate to what I saw being discussed. Oh, and "TextFile" should be spelled "IO::File::Text", IMHO. Possibly, but would need a hufmanized alias for common use. Possible just "file": s/file/open/ and we're back where we started. my Str $text is file("foo.txt") does no_follow_symlink does no_create; my $text = open("foo.txt" :no_follow_symlink :no_create); I don't think anyone (read: Larry) has declared exactly what the capabilities of the default file handle object are yet. It seems me that you could very well get what you want. -- Rod Adams
Re: Why do users need FileHandles?
Dave Whipp wrote: Under the hood, I don't really care, as long as it works (and is sufficiently efficient). There are obvious implementations that might be a bit inefficient on the first iteration (e.g. close and reopen). Quite frankly, the number of times I open unstructured files in rd/wr mode in a typical program can be measured on the fingers of one foot! If I want to do a R-M-W operation then I do like -i, and use a tmp file. Maybe the hypothetical TextFile object would do the same (by default). If I want to micromanage the actual access to the file object, then I'd be happy to c a module that lets me manipulate file handles directly. I just don't see that as the common case. Your case 2 is easy: "my Str $passwds is File("/etc/passwd") is const". With that, we might even catch your error at compile time. /file/open/ and we're back where we started. Except that we've lost a layer of abstraction: the programmer manipulates a file's contents, not its accessor. Text files would be just an implementation of strings. No need to learn/use a different set of operators. Want to read bytes: use $str.bytes. Graphemes: $str.graphs. Also, we use the existing access control mechanisms ("is rw", "is const", instead of inventing new ones to pass to the C function as named-args). I think part of the "mental jam" (at least with me), is that the read/write, exclusive, etc, are very critical to the act of opening the file, not only an after the fact restriction on what I can do later. If I cannot open a file for writing (permissions, out of space, write locked, etc), I want to know the instant I attempt to open it as such, _not_ when I later attempt to write to it. Having all these features available to open as arguements seems a much better idea to me. It's "Open a file with these specifications", not "Open a file, and then apply these specifications to it". I do admit there is merit to your abstraction system, but IMO, it belongs in a library. -- Rod Adams
Re: Why do users need FileHandles?
Austin Hastings wrote: --- Rod Adams <[EMAIL PROTECTED]> wrote: I think part of the "mental jam" (at least with me), is that the read/write, exclusive, etc, are very critical to the act of opening the file, not only an after the fact restriction on what I can do later. But why? I'd argue that this ties in to the verbose/exception discussion of a few weeks back: if the operation fails, let it pass an exception up the chain that can be caught and resolved (once) at a high level. Guess I'm still in the open "foo" or die; mentality. Given that file processing is so common in Perl, it deserves a high huffman scoring. The best way to do that is to abstract the operations away and replace them with a single declaration of intent. That declaration, of course, becomes a front-end for C or heavily optimized parrot. In a heavily OO paradigm, there would be a swarm of subclasses of type stream -- istream, ostream, iostream, exclusive_iostream, whatever. Is my $file = append_text_stream "foo.txt"; really so much better than my $file = open ">>foo.txt"; I'd strongly prefer having a few, extremely flexible, orthoganal, and complete tools, that DWIM the common case for me, than to have to sort through a long list of classes to get what I'm looking for. Now, there's nothing stopping open from returning an object of class FileHandle::OStream::Text::Exclusive or whatever. And that object can have lots of useful methods to play with. But let me describe to open what type of file I want, and let it sort it out. Another part of me that resists this is that I don't necessarily agree with a heavy OO paradigm. I've written several large projects in both a OO environment, and non-OO. I have almost always found the OO paradigms force me to convert what I wanted to do into something much more painful than the non-OO methods. It typically breaks down into the moment you want to do something to an object that the class designer did not take into account, you basically have to either rebuild parts of the object heirarchy from scratch, or get into really ugly things like declaring everything a friend of each other, or having to many accessor method calls you can't help but slow the whole program down. Also, my experience is that when following a heavy OO paradigm, you often fall into the trap of "There is only one way to do it. Why would you ever want another?" Is all OO bad? of course not. I use for several things, on a frequent basis. Is something that's OO necessarily better than something that's not? Despite the rumors from the Java crowd, no. So while I embrace Perl6 having extremely strong OO capabilities, I will argue strongly against it taking over the language. If I cannot open a file for writing (permissions, out of space, write locked, etc), I want to know the instant I attempt to open it as such, _not_ when I later attempt to write to it. Having all these features available to open as arguements seems a much better idea to me. It's "Open a file with these specifications", not "Open a file, and then apply these specifications to it". But why? Do you really open files and then perform an hour of work before attempting to use them? I'll argue that's not the normal case; rather, the normal case is something like open or die ... other_stuff() while (...) { print ... } close and the intervening delay (other_stuff) is negligible in wall-clock terms: when a failure occurs, the user hears about it immediately. It's often that I'll open a file to make sure I can save my results, then begin some process that is better measured in hours than seconds, and then begin outputting. It's not infrequent for me to have a list of five or six open statements at the start of a long process, and then close them all at the end. I do admit there is merit to your abstraction system, but IMO, it belongs in a library. I think rather that the abstraction should be the default, and the individual "I don't trust Perl" functions should be available as separate entry points if the user explicitly requires them. TMTOWTDI can apply here, I believe. You give me my way, I'll give you yours. Leave me open with all my parameters, and you can have your list of file abstraction classes. I could see having those classes part of core, if there's enough support for them, and then something simple like "use Files;" to turn them on. Just my 2¢. -- Rod
Re: Progressively Overhauling Documentation
Juerd wrote: David Green skribis 2004-08-23 11:30 (-0600): One of the selling features (or one of the features that is always sold) of POD is that you can mix it with your code. Except nobody does, at least I can't recall that last time I saw a module that did that, and I don't think I've ever really done that myself. The POD usually sits in a lump at the end of the file. I'll consider inline documentation when POD can be inlined. But as long as =command paragraphs need to start in the first column, I'm not interested in this feature. What if we add C attribute that the execution compiler would discard, but POD compilers (and debuggers) could make use of? I believe that would even allow a particularly stringent corporate policy to create a flavor of 'strict' which required documentation of various classes of elements (though whether anyone would work there is another question...). But imagine debugging code, and being able to quickly see a comment on a variable you can't figure out. Juerd's sample would become: sub foo :doc("take an Foo::Bar, and foo it over.") ( Foo::Bar$bar:doc("what to foo up."), Quux::Xyzzy $xyzzy :doc("Xyzzy to foo bar with"), +$verbose, +$foo } returns Array | undef { # real code here } -- Rod Adams
Pipeline Performance
Over in the Perl Question of the Week list, ( http://perl.plover.com/qotw/ ), we entered a discussion of the performance, or lack thereof, of pipelining in Perl 5. Randy Sims's example code demonstrates this well, and is attached at the bottom of this post. The overall point is that pipelining arrays is significantly slower than unraveling the pipeline and creating a for or while loop, largely due to the temporary lists that must be created. My question is, is there anything that can be done within Perl 6 to help alleviate this issue. It would seem that there are basically two types of functions which get placed into a pipeline: sequential and non-sequential. Sequential functions, like map and grep, do not need the entire input list to begin generating output. Non-sequential functions, like sort and reverse, need the entire input list before any output can be generated. In this regard, non-sequential functions cannot helped. But sequential ones, on the other hand, should not need to collect their entire input before passing on output. I've seen discussions of lazy lists around here before, but I forget the context. Could one write a lazy version of C, which only reads an input when an output is being requested? And therefore something like: @x = @y ==> map lc ==> grep length == 4; Would behave quite differently from: @temp = map lc, @y; @x = grep length ==4, @temp; in that no version of @temp (even internal) is needed. Of course, I'd want to be able to construct my own map like functions, and have creating them with pipeline performance in mind to be easy. Just a thought, since with the creation of ==> and <==, pipelining is bound to become an even more common construct. -- Rod Adams Randy Sims's test case: #!/usr/bin/perl use strict; use warnings; use Benchmark qw(cmpthese); my $dict = 'projects/qotw/words'; # prime disk cache open( my $fh, $dict ) or die; my @result = <$fh>; close( $fh ); cmpthese( 10, { 'simple' => sub{ simple( $dict, 5 ) }, 'compound' => sub{ compound( $dict, 5 ) }, }); sub simple { my( $dict, $word_length ) = @_; open( my $fh, $dict ) or die; my @result; while (defined( my $line = <$fh> )) { chomp( $line ); $line = lc( $line ); push( @result, $line ) if length( $line ) == $word_length; } close( $fh ); } sub compound { my( $dict, $word_length ) = @_; open( my $fh, $dict ) or die; my @result = grep length( $_ ) == $word_length, map { chomp; lc } <$fh>; close( $fh ); } __END__
Re: Pipeline Performance
Aaron Sherman wrote: On Mon, 2004-08-30 at 16:34, Rod Adams wrote: @x = @y ==> map lc ==> grep length == 4; I would think you actually want to be able to define grep, map, et al. in terms of the mechanism for unraveling, and just let the optimizer collapse the entire pipeline down to a single map. To propose one way of doing it (and really just a simple example off the top of my head which may not be the best idea...): macro grep(&cond, [EMAIL PROTECTED]) is mapper { if cond($_) { ($_) } else { () } } macro map(&cond, [EMAIL PROTECTED]) is mapper { cond($_) } Which would do two things: 1. Define a subroutine of the same name that does the full map: sub grep (&cond, [EMAIL PROTECTED]) is mapper { my @result; for @list -> $_ { push @result, $_ if cond($_) } return @result; } 2. Populates an optimizer table with just the macro form When you see C now, you can just consult that table and determine how much of the pipeline can be transformed into a single map. There, you're done. No more pipeline overhead from list passing. Now, of course you still have things like sort where you cannot operate on single elements, but those cases are more difficult to correctly optimize, and lazy lists won't help those either. So if I was to write my own function, and wanted it to be in the middle of a pipeline, but I wanted it to have a lazy evaluation feature, how would I write that? For reference, let's use the following problem: Take as input a list of numbers. For every five numbers, return the median element of that grouping. If the total list length is not divisible by five, discard the rest. (Not the most useful, but this is just example code). Basic sub to do this: sub MediansBy5 ([EMAIL PROTECTED]) { my @result; while @list.length >= 5 { push @result, (sort @list.splice(0,5))[2]; } return @result; } I would suspect that this would not be evaluated in a lazy manner, especially because I'm pooling the results in @result. One solution I see to this would be to have a "lazy return" of some kind, where you can send out what results you have so far, but not commit that your execution is over and still allow further results to be posted. For lack of better word coming to mind, I'll call a "lazy return" C. Example above becomes: sub MediansBy5 ([EMAIL PROTECTED]) { while @list.length >= 5 { emit (sort @list.splice(0,5))[2]; } } And then you could have the relatively simple: sub grep (&cond, [EMAIL PROTECTED]) { for @list -> $_ { emit $_ if cond($_); } } sub map (&func, [EMAIL PROTECTED]) { for @list -> $_ { emit func($_); } } Thoughts? -- Rod Adams
Re: Synopsis 9 draft 1
Larry Wall wrote: On Fri, Sep 03, 2004 at 05:45:12PM -0600, John Williams wrote: : What happens when the Pascal programmer declares : : my int @ints is shape(-10..10); : : Does it blow up? No. : If not, does @ints[-1] mean the element with index -1 or the last element? The element with index -1. Arrays with explicit ranges don't use the minus notation to count from the end. We probably need to come up with some other notation for the beginning and end indexes. But it'd be nice if that were a little shorter than: @ints.shape[0].beg @ints.shape[0].end Suggestions? Maybe we just need integers with "whence" properties... :-) Larry What jumps to my mind is that inside an array subscript could be (sub)?context of it's own. Then one could do: @ints[.beg .. .end ; .beg + 3 .. .end]; Where the .beg and .end would relate to @ints.shape[0] or @ints.shape[1] depending on which position it's in. My only issue with this, and why I refered to it as a possible subcontext, is that it's easy to concieve of somewanting to use the prior context to generate the subscripts for an array. The other idea which jumps to mind was to create an operator which tell the compiler to treat the the following number as if it referred to a 0-based (sub)array, and negatives count off the end. What springs to my mind is that we are saying this is the "relative to start / end" of the range, so I will call it Î (capital delta). @ints[ Î0 .. Î-1 ; Î3 .. Î-1 ]; It at least looks nice. -- Rod
Re: parameter contexts (was: Synopsis 9 draft 1)
Larry Wall wrote: I'm still thinking A is the first one and Z is the last one. Someone talk me out of it quick. I had thought about A and Z before my previous post. I dismissed it for two reasons: 1) Using Alphas as an index for something that should be numeric can be very confusing. Especially when one sees: @Int[4 .. Z]; 2) If A = first and Z = last, DWIM (but maybe not DWYM) would dictate that I should be able to say: @Int[C .. Y]; instead of: @Int[A+2 .. Z-1]; That's why I liked the concept of an operator to modify the number afterwards. Okay, Î might not have been the best choice, but there are other options. Looking at your preferred Latin-1 table, we have:  (§) "Use this Section of the array"  (®) The R means "Relative to base" Or if we want to get silly, use  instead of .., and just use the numbers as is. If you insist on using A and Z, at least make them \A and \Z, to give a stronger visual cue that something different is happening. -- Rod
Re: Pipeline Performance
Luke Palmer wrote: Jonadab the Unsightly One writes: Rod Adams <[EMAIL PROTECTED]> writes: One solution I see to this would be to have a "lazy return" of some kind, where you can send out what results you have so far, but not commit that your execution is over and still allow further results to be posted. For lack of better word coming to mind, I'll call a "lazy return" C. Example above becomes: sub MediansBy5 ([EMAIL PROTECTED]) { while @list.length >= 5 { emit (sort @list.splice(0,5))[2]; }} That's actually a very good idea. That's why Perl 6 has it :-) sub MediansBy5 ([EMAIL PROTECTED]) { gather { while @list >= 5 { # there's no .length; it's .elems take (sort @list.splice(0,5))[2]; } } C returns a list of everything that was Cn inside of it. It does this by building a coroutine out of its argument, so it works lazily. Luke Better documentation on gather/take is merited. Before starting this thread, I did a search on gather/take, thinking it might be what I needed, but all I could find was in A12 : "We snuck in an example the new |gather|/|take| construct. It is still somewhat conjectural." This was not very informative. Not to mention, it should be in S4/S9, not A12. I would question the need for C, however. Could not a lone C/C force the return value of the enclosing routine/closure to be a lazy list, and here's a few values to get things started? To address Jonadab's questions: 1. What if anything do you propose is the evaluation value of emit? The lazy list being constructed. Maybe a reference to it instead. 2. Should a subsequent implicit return behave differently than usual if some values have already been emitted? This is a bit harder, but I would think it should emit it's parameters, then exit the routine. The downside would be it forces list context where it might not have existed before, but it's the most consistent thought I have. One other question: Would emit behave differently if the sub is called in a non-list context, such as void context or a scalar context? My thought is that it returns a lazy list, and P6 rules for converting such a thing into a void or scalar would apply. -- Rod Adams.
Re: S5 updated
Luke Palmer wrote: Edward Peschko writes: Ok, fair enough.. although I'm not sure that I'm all that sure I'm completely happy-with/understand the syntax described in that article. It works for the trivial cases, but what about complex grammars? It works for anything. It gets pretty inefficient in the case of code assertions, but there's no way around that. Testing your assertions isn't going to be the useful thing about this, anyway. Eyeballing and fixing the regular expression then becomes trivial (or relatively trivial). I definitely see the use. You just pass it to generate. It recursively calls itself until it's down to constant strings, which are always a well-defined match (or character classes, which are tricky and computationally intractible in the presence of unicode). I love programming in theoretical Perl 6. Luke Now this is truly useful. Especially when one realizes that all of Perl 6 is already expressed in these handy regular expressions. It's therefore possible to generate all possible Perl 6 programs, then simply see which one(s) satisfy your test cases, and there's no need to do any silly programming ever again! And just think... All the p6c group has to do is a little prep work, and P6 will then write itself! Just think of the marketing ploy: "Other languages were written _in_ themselves. Perl was written _by_ itself." This solution definitely has Laziness and Hubris going for it, though I suspect it may be lacking in the Impatience department. (I need more sleep) -- Rod Adams
Re: S5 updated
Edward Peschko wrote: Well, there re two responses to the "that's not a common thing to want to do": 1) its not a common thing to want to do because its not a useful thing to do. 2) its not a common thing to want to do because its too damn difficult to do. I'd say that #2 is what holds. *Everybody* has difficulties with regular expressions - about a quarter of my job is simply looking at other people's regex used in data transformations and deciding what small bug is causing them to fail given a certain input. Running a regular expression in reverse has IMO the best potential for making regexes transparent - you graphically see how they work and what they match. So would this get used? Yes - far more IMO than *other* parts of the language that already are sanctified: continuations, for example. I have to disagree here. I've also been the head of a major data transformation project that used P5 RE engine as a workhorse. And yes, they are a pain to debug. But I really don't think that a RE --> string generator is the solution. What's wrong with it? Quite simply, they can generate way too many different results, and finding the ones that will give you insight can be challenging at best. I imagine it seeing the first * or + and then generating an infinite number of strings for just that. What logic would you impose to truncate this list in a "standard" way? Given a long list of possibilities, I'd be tempted to write a different RE to scan the matches of the generation of the first RE, and how should I then debug the second ones? Also, showing a list of _what_ that RE does match gives no clues as to _why_ it matched it, or moreover, why it _didn't_ match what you wanted. I just don't see it as being useful. Oh, and I'd disagree with "*Everybody* has difficulties with regular expressions". If after a month of working on my project, if you still had troubles building/modifying RE's, your job future there would be in serious question. But I never had a problem with that. Once people got up to speed, it was mainly just the tedium of dealing with the volume of rules and data that got to people. And for reference, outright nasty RE's were fairly commonplace. There's simply no way to graphically show regexes now. Even use re 'debug' is terribly cryptic. The best way to deal with them right now is to burn a regex parser into your brain. Ahh... Now this is the real problem. People need someway to better see how a given RE attacks a given string. I see potential for a standalone program that acts as a "RE analyzer". Inputs would be a RE and a string. Output would be a step by step graph of the internal logic used to match / not match the string. I'd break the RE up into the same pieces the Engine does, then show how that subrule matched char a, then char b, but failed to match c, so it backtracked to a, etc. I envisions three columns: partial string matched so far, partial RE used to match it, and whatever flags or comments the engine wishes to make at this juncture. The beauty of this solution is, if Perl6 and/or Parrot (not sure which is the better choice) provides a few hooks into the P6RE Engine, it would be absolutely authoritative, and could even handle cases where the rules changed due to module loading. And since I'd expect those hooks to be in there anyways for other reasons (mainly, letting people muck around with how they work), I'd suspect all the "Core support" needed would already be there (I may be wrong.). But it doesn't need to be core. A friendly side project, possibly mentioned in the core documentation as a learning tool, would do the job nicely. And it doesn't need to be discussed on p6i, p6l, or p6c, at least not for a very long time. Or we could just burn a RE parser into everyone's brain, as you mentioned. That'd also work. -- Rod Adams
S10/11 Questions
Some questions: - Can we get an AUTOCLASS/AUTOCLASSDEF hook pair? - How does one create a class with a hyphen in the middle of it? If I say: use Foo-Bar; will it complain about not finding a Bar version of Foo? Would I instead need to say: use 'Foo-Bar'; use Foo\-Bar; use ('Foo-Bar'); $x = 'Foo-Bar'; use $x; btw, that last one would be really handy sometimes, but for other reasons. - If we do: use Dog-1.2.3; use Dog-2.0.1; my Dog $spot; What do we get? Okay, I know, an error message, but is it on line 2 or line 3? Can we instead do something like: use Dog-1.2.3; use Dog-2.0.1 is rename(newDog); my newDog $spot; - There needs to be some definition of what happens when more than one module matches a given wildcard in 'use'. Something like: 1. Throw a warning 2. Pick the highest version, then the earliest source in the alphabet of course, there should be a way to flag it to work in other ways, so some project could have a standard: use ($^name ~~ /^Project::/)-(Any)-TPFBundle; meant to include all the modules made thus far. And yes, I can come up with times when this would be useful. - I see some utility in having an optional sub-source or version code thingy. Something like: use Dog-(Any)-(Any)-Stable; use Canine-(Any)-(Any)-Development; - Can we get a hook that gets called when 'use' fails to find module locally? I see potential for: use AutoCPAN; use Some::Module::Not::Currently::Loaded; hmm. that doesn't work, since you typically won't be including the cpan author code if you don't have to. CPAN, or some other public source would be a definate security risk, and thus to be discouraged, but it should be possible to write the thing. I've heard of sites who had massively distributed mod_perl servers, where all the code past a simple stub was stored in a central RDBMS. Made releases and version control much nicer. - By saying #!/usr/bin/perl6 forces Perl 6, I assume you mean : "The compiler sees /:i ^#! .* perl6/ on the first line". - -- Rod Adams
Re: S10/11 Questions
Larry Wall wrote: On Tue, Nov 09, 2004 at 09:18:47PM -0600, Rod Adams wrote: : Can we get an AUTOCLASS/AUTOCLASSDEF hook pair? Considering a class is just a variable in another symbol table, seems like an AUTOVAR in the container might cover it. I guess I don't understand enough of how P6 is being built, but wouldn't a similar argument hold for AUTOMETH and AUTOSUB? : $x = 'Foo-Bar'; use $x; : : btw, that last one would be really handy sometimes, but for other reasons. All symbolic indirection is done with ::($expr) in Perl 6, so it'd be use ::('Foo-Bar') Very nice. : If we do: : : use Dog-1.2.3; : use Dog-2.0.1; : my Dog $spot; : : What do we get? Okay, I know, an error message, but is it on line 2 or : line 3? Presuming we add some way to do aliasing, line 2 would give an error. : Can we instead do something like: : : use Dog-1.2.3; : use Dog-2.0.1 is rename(newDog); : my newDog $spot; More likely something on the order of module newDog ::= (use Dog-2.0.1); where it's only a "use" in a void context that implicitly uses the same short name as the alias. But like I said, it's not even clear that the pseudo listop syntax of "use" is the right way to handle this. Maybe it's just an "isa"-like thing: my module newDog is Dog-2.0.1; or maybe it's more like a role: my module newDog does Dog-2.0.1; But maybe it's something else again that we just haven't thought of yet. I'm largely indifferent to the exact syntax involved, as long as I have some way to loading two different versions of the same module, and can then differentiate between them in my code. Possible reasons for loading two versions of the same thing: 1) Retrograde testing. You just built a new version, and you want to have the two versions running side by side through the test cases, without having to kick off a new instance. 2) The nifty new version has a whiz-bang function you really need, but in the process of upgrading, it broke some other whiz-bang function. 3) The two really are not the same thing, they were just given the same name. There are some separate benefits of module aliasing, aside from loading like-named modules, to consider: 1) The module is named something like "AudioFile::Info::Ogg::Vorbis::Header::PurePerl", and you'd rather not type it more than once. 2) You just changed your entire module naming scheme, and want a stop gap measure for all you code that's still referring to the old names. : There needs to be some definition of what happens when more than one : module matches a given wildcard in 'use'. : : Something like: : 1. Throw a warning : 2. Pick the highest version, then the earliest source in the alphabet I think you're assuming version numbers contain alphabetics. I'd like to stay away from that if possible. Nope, I wasn't. I was using the word "source" where you were saying "author". But I think #2 is far and away the most common intent with a wildcard on version numbers. I don't know what the pecking order should be among authors, but as someone who has suffered from being a W, it's not going to be alphabetical. :-) My wife didn't believe me till she married me and moved from B to W. Maybe #1 is a suitable response for multiple matching authors. Or maybe it should just pick one randomly to keep people honest. As one with a last name starting with "ADA", I can't say I've noticed any problems with alphabetical. =). As for picking "randomly", I think a more deterministic method would be in order. But something that can't be easily abused by naming it "". How about the following rules for multiple wildcard matches: 1) If the version numbers differ, pick the highest. 2) else, throw a warning (error if strictures), AND 2a) if one is in a directory earlier in @INC than the other(s), use it. (Allow users to have a local copy override a global one). 2b) else, pick the one with the lowest CRC32 value of the Author : of course, there should be a way to flag it to work in other ways, so : some project could have a standard: : : use ($^name ~~ /^Project::/)-(Any)-TPFBundle; : : meant to include all the modules made thus far. And yes, I can come up : with times when this would be useful. That sort of thing should be hidden in a metamodule. In any event, it doesn't give a good name to alias to. metamodule. hmm. That brings us back to Aaron Sherman's topic of re-exportation. How does one make a metamodule which uses other modules, and has those modules' exports available to metamodule's caller, as if the caller had instead called all of those modules in addition to the metamodule? (And placeholders only work inside closures.) Grr. My web browser used a font that does not adequately distingui
Re: can gather/take have multiple bins
Dave Whipp wrote: gather @bin1, @bin2 -> $bin1, $bin2{ for @words { $bin1.take if /^^a/; $bin2.take if /e$$/; } } Juerd point out (private email) that my example doesn't really make any sense in that it doesn't do anything over and above s/take/push. However, I think the concept of multiple bins could still be useful. My understand of gather/take is that the function that does the "gather" is coroutined (if that's a verb) against the block that does the gathering. So to be able to usefully use multiple streams, the "gather" would need to fork into multiple threads that are then interleaved with the "gather" block. Calling a function in junctive context does the forking bit, so a gather that gathered in a junctive context might make sense as a serialization mechanism. I can't quite work out what the syntax would be for that though. Okay, thinking a bit about this, I agree that there are times when you want multiple lazy lists going on at the same time. But, frankly if the lists are lazy, why shouldn't the programmer be lazy as well? @bin1 = gather { for @words { take if /^^a/; } } @bin2 = gather { for @words { take if /e$$/; } } Two lazy lists? Two gathers! Since they are lazy, you can eval them in order you please. I see a problem with attempting to put the two into one statement. In your example above, if you wanted something from @bin2, you could have to process a whole lot of things into @bin1, just to get the next element out of @bin2. In fact, you could easily end up processing all of @words, and filling @bin1, only to discover that @bin2 is empty. To me this kind of forced-fill of @bin1 is a complete defeat of the entire concept of _lazy_ lists. There's also the issue of from what I understood of gather/take before (still awaiting a proper definition), gather returns a lazy list. So it's not C, it's C<@bin1 = gather {...}>. What would your C return? A list of lazy lists? How do you easily tell the difference between a list of lazy lists and a lazy list? I think it's better to leave a 1::1 gather::list ratio, as that will cover some {insert randomly high %age} of all cases. For the other cases, you're likely better off building a class with two emitter methods, and possibly even use C to make it look like two lazy lists. -- Rod Adams The thing about lists is that they are linear. They are, by definition, a sequence of single items. Now, that 'single item' may very well be a reference to something non-trivial, but to the list it's a single value.
Hyper Here-Docs? (was: Re: angle quotes for here-docs ?)
Juerd wrote: Thomas Seiler skribis 2004-11-25 14:52 (+0100): Is $heredoc = «END; the same as $heredoc = < I certainly hope not. Quoting the delimiter is needed, by the way. How is <<'END' disambiguated from <<'qw' list>>, anyway? Seeing the « in the context of a here-doc made me think "can you do a »<< here-doc?" So, something like : @text = »< text2 END text3 END text4 END for @text { ...} The hard question about this is: how do you know when you've hit the last END? especially if the text you're loading looks like Perl code, or if you have different < btw, should it be »<<, <<«, or »<<«? -- Rod Adams
Re: Angle quotes and pointy brackets and heredocs
On Fri, Nov 26, 2004 at 07:32:58AM +0300, Alexey Trofimenko wrote: I notice that in Perl6 thoose funny « and » could be much more common than other paired brackets. And some people likes how they look, but nobody likes fact that there's no (and won't!) be a consistent way to type them in different applications, wether it's hard or easy. But to swap «» with [] or {} could be real shock for major part of people.. We also have another ascii pair, < and > . maybe they could be better than « and » ?:) i'm not that farseeing, but isn't problem of distinguishing < as a bracket and < as an comparison operator no harder than distinguishing << as bracket and as part of heredoc?.. Speaking of heredocs. Are they really common enough to merit a "two char, absolutely no whitespace after it" lexical? Especially one that looks a lot like the left bitshift operator, as well as an ASCII version of a Unicode quoting and splitting character? What if instead, we add a different adverb to q// and qq//? something like :h. That way people can mix and match all the quoting option they want, and we remove some annoying requirements about when you can and cannot have /<<\s+/ in your code. P5: print <<"END", " done.\n"; line 1 line 2 END P6: say qq:h/END/, "done."; line 1 line 2 END As for the topic being discussed, Since < and > are now full class quote-like thingies in P6REs, much to the chagrin of those of us who parse html on a regular basis, using them as such in the rest of P6 makes sense as well. Parsing should not be hindered since one would occur in operator context, and the other in expression context. -- Rod Adams
Re: Angle quotes and pointy brackets
Brent 'Dax' Royal-Gordon wrote: I like this in general. However... Larry Wall <[EMAIL PROTECTED]> wrote: * Since we already stole angles from iterators, «$fh» is not how you make iterators iterate. Instead we use $fh.fetch (or whatever) in scalar context, and $fh.fetch or @$fh or $fh[] or *$fh in list context. I believe you tried this one a couple years ago, and people freaked out. As an alternative, could we get a different operator for this? I propose one of: $fh -> $fh» (and $fh>>) $fh> All three have connotations of "the next thing". The first one might interfere with pointy subs, though, and the last two would be whitespace-sensitive. (But it looks like that isn't a bad thing anymore...) Any other suggestions, people? ++$fh
Re: Arglist I/O [Was: Angle quotes and pointy brackets]
Larry Wall wrote: So you can say for =$*IN {...} for =$*ARGS {...} for = {...} for = {...} for =«$foo.c $foo.h» {...} for =['foo.c', 'foo.h'] {...} for =['.myrc', @*ARGS] {...} for [EMAIL PROTECTED] {...} for =<> {...} The simplicity is nice, but the visual message is, well, icky. It might be salvageable by having the ='s balance, yielding: for =$*IN= {...} for =$*ARGS= {...} for == {...} for == {...} for =«$foo.c $foo.h»= {...} for =['foo.c', 'foo.h']= {...} for =['.myrc', @*ARGS]= {...} for [EMAIL PROTECTED] {...} for =<>= {...} That looks better. Might even make the trailing = mean something useful like "auto-chomp". And I don't think it'll be visually confusing to people who put spaces on both sides of their assignment operators. But those of us who often use the horizontal ws to break up the terms on a line will moderately often not put spaces around our assignments and less thans. Okay, this rant is more about the \s<\s than \s=\s. To me, it is easier to understand the grouping of line 1 than line 2 below: if( $a<$b && $c<$d ) {...} if( $a < $b && $c < $d ) {...} In line2, my mind has to stop and ask: is that "($a < $b) && ($c < $d)", or "$a < ($b && $c) < $d". It quickly comes to the right answer, but the question never comes up in the first line. If I wanted to use more parens for clarity, I'd use LISP. -- Rod Adams
Re: pull & put (Was: Angle quotes and pointy brackets)
Brent 'Dax' Royal-Gordon wrote: Smylers <[EMAIL PROTECTED]> wrote: Yes. C is a terrible name; when teaching Perl I feel embarrassed on introducing it. C's only virtue, IMHO, is that it's clearly the inverse of C. But I think the spelling and aural relationship between C, C, C, and C is clear enough to negate that. But then, I'm a little biased. Except that push and pull are logical opposites linguistically, but not in standard CS parlance. could be very confusing. There's a possibility of using C and C for enqueue/dequeue, except that C == C in standard implementations. So C and C? yeck. -- Rod Adams
Required whitespace issues.
Alexey Trofimenko wrote: On Sat, 04 Dec 2004 11:03:03 -0600, Rod Adams <[EMAIL PROTECTED]> wrote: Okay, this rant is more about the \s<\s than \s=\s. To me, it is easier to understand the grouping of line 1 than line 2 below: if( $a<$b && $c<$d ) {...} if( $a < $b && $c < $d ) {...} In line2, my mind has to stop and ask: is that "($a < $b) && ($c < $d)", or "$a < ($b && $c) < $d". It quickly comes to the right answer, but the question never comes up in the first line. If I wanted to use more parens for clarity, I'd use LISP. I've got used to write it as if( $a < $b and $c < $d) {...} already. if it could help.. :) Yes, I know all about being able to use 'and' instead of '&&', and that does make things a bit more readable. But I prefer to reserve 'and/or' for those cases where you really need the ultra loose binding. Like when you have assignments mixed in. Not to mention that when you remove the ()'s on control structures, it's easy to confuse the reader (but likely not the parser) as to whether your inside the conditional, or outside of it, since and/or are often used as a poor man's if. $y++ while $a < $b[$bar]{$baz = =<'foobar'>} and $c = $d; Not that I'd actually ever write something that obscene. I'm deciding I don't like the unary = proposal, for similar reasons to <. It feels like we are rapidly approaching the point where all binary operators require surrounding whitespace, to distinguish them from similar looking unary/quoting operators. There are at least enough of them, including fairly popular ones like = and <, (but not necessarily >), that allowing some of them to be \S\S is bound to cause a great deal of confusion. In fact, unary = imposes whitespace requirements on all ops that end in =. So I would suggest that P6 adopt one of the following: 1) \S\S is allowable for for all . 2) \s\s is required for all , save method postfix ones. Pros \S\S : - very P5ish - allows users great flexibility on how they logically group terms in more complex expressions - one liners get easier, especially on platforms that have troubles passing args with whitespace in them. Cons \S\S: - requires a great deal of reworking to remove ambiguity with similar looking unary ops. - can make code indistinguishable from line noise at times. Pros \s\s : - opens up the realm of available binary and unary/balanced ops considerably. - makes life easier for the lexical analyzers. - forwards compatible with new operators, including user defined ones. Con \s\s: - very imposing for an otherwise programmer friendly language. - makes obsfication contests a lot harder. Personally, I would very much prefer \S\S. But I strongly suspect that removing all the conditions where \s\s is needed is a lost cause at this stage on the game. So barring that possibility, I'd vote for the consistency of \s\s. But I still wouldn't like it. For reference, here is a list of the operators that have some form of whitespace issue so far: = := ::= += -= *= **= .= /= //= ||= &&= %= < <== +< >= <= == != =:= all the alpha ops +<< ~<< many hyper variants of operators .. # 0 .. .length() vs 0 ... length() likely others as well. -- Rod Adams
Re: Required whitespace issues.
Larry Wall wrote: On Sat, Dec 04, 2004 at 08:14:17PM -0600, Rod Adams wrote: : In fact, unary = imposes whitespace requirements on all ops that end in =. Not true. I guess not all cases. But several do in certain situations. $x ==<$foo>; # $x == <$foo>; $x = =<$foo>; @x <==<$foo>; # @x <= =<$foo>; @x <== <$foo>; $x//=<$foo>; # $x // =<$foo>; $x //= <$foo>; [EMAIL PROTECTED]; # $x ** [EMAIL PROTECTED]; $x **= @y; Enough to make my overall issue of "an increasing number of operators are acquiring whitespace requirements" valid. If I'm not mistaken, \S<\S is invalid, but \S>\S is valid. The rest of my post can be summarized as "A consistent set of rules about when whitespace is and is not allowed are in order." -- Rod Adams
Re: Required whitespace issues.
Larry Wall wrote: <>On Sat, Dec 04, 2004 at 08:55:00PM -0600, Rod Adams wrote: : $x ==<$foo>; # $x == <$foo>; $x = =<$foo>; : @x <==<$foo>; # @x <= =<$foo>; @x <== <$foo>; : $x//=<$foo>; # $x // =<$foo>; $x //= <$foo>; : [EMAIL PROTECTED]; # $x ** [EMAIL PROTECTED]; $x **= @y; In each of those cases the longest-token rule comes into effect. That's not only consistent, but standard CompSci for the last 30 years or so. The only person who will get burned on those is someone who insists on *not* putting whitespace in front of unary = when it would be ambiguous. I have negative sympathy for such people. <>Well said! Although I by no means dispute that longest token rule is a long term standard in language design, I will claim that many programmers, including myself before this, are unaware of it. So I will now change my concerns to: "The longest-token rule needs to be mentioned in S03, and explained in a future perlop.pod." -- Rod Adams
Re: pull & put (Was: Angle quotes and pointy brackets)
Dan Brian wrote: If I went with "get", the opposite would be "unget" for both historical and huffmaniacal reasons. But "get" has too strong a class accessor connotation in most OO. "unpull?" ;-) pushf/popf. f is for "front". But I still don't see anything wrong with shift/unshift. I'd prefer to avoid having a group of words that all mean about the same thing, but keeping them straight requires some memory trick. I program in too many languages to keep my mnemonics straight. There's going to be enough fun with is/has/does/but. For reference, I always have to do a 'perldoc perlvar' when I need a P5 $. -- Rod Adams
Auto My?
Considering that "proper" and common usage, not to mention strictures, dictates a heavy insistence on 'my'. I will thus assume that creation of lexical variables with 'my' far out numbers the creation of package space globals. Should we not then have it where it's the default behavior, and creation of package ones take explicit declaration (via 'our')? Well, at least when strictures are on. When they are off, the coder is obviously playing fast and loose, and should get the easy 'everything global' behavior. What issues am I overlooking here? -- Rod
Re: Auto My?
James Mastros wrote: Juerd wrote: Just typing "my " before the first use of a variable isn't hard, and it makes things much clearer for both the programmer and the machine. Does this imply that it's now possible to type C, and declare @foo? In the current perl, this doesn't work -- it's a syntax error. It'd certainly make many constructs easier. I see why that's an error. It can be very confusing In literal fashion you are attempting to make the 24th element of @foo lexical, and having some elements of @foo have different scope from the rest is a bad idea. However, I have also been bitten by that rather frequently, though with a different construct. Typically it's with hash slices: my @[EMAIL PROTECTED] = @[EMAIL PROTECTED]; # ERROR! my %newhash; @[EMAIL PROTECTED] = @[EMAIL PROTECTED]; # Okay, but not as convienent. This was part of the reason I spawned this thread. But it was also due to being in the middle of trying to write some decent quality code under a heavy time pressure, and noticed that >50% of my lines had a 'my' on them. It's typically not that high of a percentage, but when you are creating lots of small utility routines, declaring all your lexicals can be a significant part of the task. I added to this the observation that lexical variables are significantly more common than non-lexicals, and thought out loud as to why I was doing more work for the common case than the uncommon case, in a language that generally doesn't have that problem. One of the other reasons in favor of the idea was aesthetic. # stuff which declares $x, $z, and $q $x = 4; my $y = 7; $z = 12; my $r = 4543; $q = 121; compared to: # stuff which declares $x, $z, and $q $x = 4; $y = 7; $z = 12; $r = 4543; $q = 121; With a fixed width font, like all code editors use, all the =' like up, and I can quickly scan the var names to get to the one I want to change at that moment. Yes, I could have added a 'my ($y, $r);' to the front of the list, but that's adding another statement to the mix, same as the hash slice above, adding considerably more weight to 'my' than just three keystrokes (m - y - space). However, given the strong opposition (with merits) to this in other responses, I am willing to live with it the P5 way. Just seemed like autolexicals was rather DWIMish. Another facet of this discussion comes into account when also specifying type. from S9: my bit @bits; my int @ints; my num @nums; my int4 @nybbles; my str @buffers; my ref[Array] @ragged2d; my complex128 @longdoublecomplex; Wouldn't this be much better as: bit @bits; int @ints; num @nums; int4 @nybbles; str @buffers; ref[Array] @ragged2d; complex128 @longdoublecomplex; Given that most of the stated reservations had to deal with explicit declaration better defining scope, what is wrong with drooping the my in this case? -- Rod Adams
Re: = vs <== [was: Perl 6 Summary for 2005-01-31 through 2004-02-8]
Larry Wall wrote: On Wed, Feb 09, 2005 at 10:04:48AM +0100, Michele Dondi wrote: : On Tue, 8 Feb 2005, Matt Fowles wrote: : : > pipe dreams : > Juerd wondered if he could mix = and ==> in a sane way. The answer : > appears to be no. Once you bring in ==> you should stick with it. : : Huh?!? It doesn't seem to me that the answer is 'no'. In fact C<< ==> >> : is supposed to be yet another operator, albeit somewhat a special one. If : I got it right the answer is actually 'yes': what Larry suggested is that : it would be _stylistically_ better to stick with it once it is used in the : first place. Yes, you can certainly intermix them as long as you keep your precedence straight with parentheses. Though I suppose we could go as far as to say that = is only scalar assignment, and you have to use <== or ==> for list assignment. That would be...interesting...to say the least. For instance, it would eliminate the guessing games about whether the syntactic form of the left side indicates a list. Doubtless there would be some downsides too... Larry I have to say that my initial reaction to this was one of disgust, but the more I think about it, the more I am warming to the idea of having a more robust method of declaring list context vs scalar context. Issues that arise (my mind has yet to settle enough to label them "downsides"): - List assignment is way too common to inflict a three char operator on, especially one that really likes having \S around it. (But don't ask me what else to use, not much is left available.) At least, it's way too common for me. - orthogonality says that we would then need a left scalar assignment operator to mimic ==>. Linguistically, this is "Calculate all this, then stuff the result into $x". This would be very nifty when building long self-referring assignments, because the assignment appears after the expression which used the previous value, which just "flows" better. . - Would C<< @x = @y; >> then mean C<< @x := @y; >>? - Somehow, C<< %x <== %y; >> feels very, very wrong. Pluses: - I've often considered list assignment to be one of the most useful and subtle things that makes Perl Perl, especially when combined with hash/array slices. However, attempting to bring less monkish fellows up to enlightenment often encounters mental blocks. This might help, having a different syntax makes it significantly less 'magical'. (even though Magic is Good, imho) I should probably stop rambling now and get some sleep. -- Rod Adams
Pop a Hash?
Does ($k, $v) <== pop %hash; or ($k, $v) <== %hash.pop; make sense to anyone except me? Since we now have an explicit concept of pairs, one could consider a hash to be nothing but an unordered (but well indexed) list of pairs. So, C<< pop %hash >> would be a lot like C<< each >>, except, of course, that it deletes the pair at the same time. If we do that, I'd also want to be able to push %x, %y; which would mean something like: %x{%y.keys} <== %y{%y.keys}; but be much easier to read. -- Rod Adams. (And now I'm really off to bed.)
Re: Fwd: Junctive puzzles.
Patrick R. Michaud wrote: Even if you fixed the =/and precedence with parens, to read my $x = (any(2,3,4,5) and any(4,5,6,7)); then I think the result is still that $x contains any(4,5,6,7). Funny. I thought $x would contain 'true' here, since C was a boolean operator. But I could be very wrong. The overall impression I'm getting here is that we need some syntax for saying: $x = any(1..1000) such_that is_prime($x); where "such_that" acts as a form of "junctive grep". so the above might mean the same as: $x = any(1..1000 ==> grep(is_prime($_))); We then can say that any junction stored in a var stays constant, until explicitly reassigned. Just like every other kind of thing we store. Philosophy Question: What's the difference between a junction and an array containing all the possible values of the junction? Other than how they are used, of course. So, on that train of thought, would this make sense: if $x == @x.any {...} if $x == @x.none {...} If this is the case, then this entire discussion collapses into how to best convert arrays into junctions and junctions into arrays. Perl's existing abilities to edit arrays should be more than sufficient for editing junctions. -- Rod Adams
Sets vs Junctions (was Junctive puzzles.)
Damian Conway wrote: Rod Adams wrote: The overall impression I'm getting here is that we need some syntax for saying: $x = any(1..1000) such_that is_prime($x); In standard Perl 6 that'd be: $x = any(grep {is_prime $^x} 1..1000); or, if you prefer your constraints postfixed: $x = any( (1..1000).grep({is_prime $^x}) ); Both of those seem way too brutal to me. We then can say that any junction stored in a var stays constant, until explicitly reassigned. Just like every other kind of thing we store. Yep. That's exactly what we'll be saying! Good. Philosophy Question: What's the difference between a junction and an array containing all the possible values of the junction? Junctions have an associated boolean predicate that's preserved across operations on the junction. Junctions also implicitly distribute across operations, and rejunctify the results. My brain is having trouble fully grasping that. Let me attempt a paraphrase: Junctions exist to be tested for something. When a test is performed, the junction is evaluated in terms of that test. A "result junction" is created, which contains only the elements of the original junction which will pass that given test. If the result junction is empty, the test fails. Looking at the S09 C<< substr("camel", 0|1, 2&3) >> example explains a lot. So, on that train of thought, would this make sense: if $x == @x.any {...} if $x == @x.none {...} Probably. It's entirely possible that, in addition to being built-in list operators, C, C, C, and C are also multimethods on Scalar, Array, and List. okay. -- Now that I've gotten some feedback from my original message (on list and off), and have had some time to think about it some more, I've come to a some conclusions: Junctions are Sets. (if not, they would make more sense if they were.) Sets are not Scalars, and should not be treated as such. If we want Sets in Perl, we should have proper Sets. Let's first define what a Set is: - A Set is an unordered collection of elements in which duplicates are ignored. - There are really only two questions to ask of a Set: "Is X a member of you?", and "What are all your member?" - Typically, all members of a set are of the same data type. (I'm in no way committed to this being part of the proposal, but it makes sense if it is) Sets and Lists are two different things. Lists care about order and allow duplicates. Iterating a Set produces a List, and one can convert a List into a Set fairly easily. Sets and Hashes are quite similar, but in other ways different. The keys of a Hash are a Set of type String. In addition to the String constraint, each element of the set has an additional scalar value associated with it. Hashes can be multidimensioned. I have no idea what a multidimensional Set is. It may be possible to represent Sets as lightweight Hashes if the "Strings for keys" constraint is lifted or altered, but I see several advantages to Sets being distinct, for reasons I'll outline below. So I propose making Sets a first class data type right up there with Arrays, Hashes, and Scalars. For the purposes of this posting, I will assume that they get a sigil of #. (to get a comment, you need whitespace after the #). I harbor no expectations that it will stay as this, but I needed something, and didn't feel like remapping my keyboard at the moment. Interestingly, on US keyboards, @#$% is shift-2345. With that, we can now make existing operators do nifty things: #a = #b + #c;# Union (Junctive $b or $c) #a = #b - #c;# Difference( $b and not $c) #a = #b * #c;# Intersection ( $b and $c) #a == #b;# Do sets contain the same values? #a < #b;# Is #a a subset of #b? likewise >, <=, >= $a ~~ #b;# Membership #a += $b;# Add value to set #a = @b; # Create a set from an array/list #a = (1,2,3); $ref = #{1..10}; # an anonymous Set reference @a = #b; # One way to iterate the members. It's probably best to define binary | and & as "Set Creation with Union/Intersection", so we have: #a = 1|3|7; #a + @b == #a | @b; We also add some methods here and there: @a = #b.values; #b = @a.as_set; $a = #b.elems; my str #a = %b.keys; I also envision "virtual sets", which cannot be iterated, but can be tested for membership against. These would be defined by a closure or coderef. #natural_numbers = { $^a == int($^a) && $^a > 0 }; #primes = &is_prime; Set operations with virtual sets should be able to define new closures based on the former ones: #a = #b + #c; ==> #a = {$^a ~~ #b || $^a ~~ #c}; #a = #b * #c; ==> #a = {$^a ~~ #b && $^a ~~ #c}; #a = #b - #c; ==> #a = {$^a ~~ #b && $^a !~ #c}; #a = #b + 3; ==> #a = {$^a == 3 || $^a ~~ #b}; So now, some
Re: Fun with junctions (was Sets vs Junctions)
Patrick R. Michaud wrote: On Sat, Feb 12, 2005 at 03:49:02AM -0600, Jonathan Scott Duff wrote: On Sat, Feb 12, 2005 at 01:03:26AM -0600, Rod Adams wrote: I also find the following incredibly disturbing: perl6 -e "$x = 'cat'|'dog'; say $x;" dog cat Would that happen though? What's the signature of C? I think it's something like multi sub *say ($stream = $*OUT: *$data) { ... } so autothreading wouldn't happen anyway as S9 says the slurpy array/hash aren't autothreaded. I reread S09, and I believe "autothreading" is the wrong term for the iteration that a junction incurs (Even though it appears in the section immediately after Junctions. Autothreading is something far weirder, dealing with partial dimensional slices, I believe. And in that case, it makes sense to turn off autothreading for slurpys, since in flattening, you get rid of the messy dimensions. Therefore I suspect that the above is wrong, and the behavior of C is still to duplicate. -- Rod Adams
Re: Fun with junctions (was Sets vs Junctions)
Patrick R. Michaud wrote: On Sat, Feb 12, 2005 at 12:41:19AM -0600, Rod Adams wrote: Of course we'll always have C. But this is Perl, and I want YAWTDI. After all, another way to test membership was just added, whereas before you pretty much just had C. ...another way to test membership was added...? $x == any(@y); My issue is less that lists and sets are radically different. It is much more a matter of Junctions and Scalars are radically different. Getting me to accept that a Scalar holds several different values at once is a hard sell. Especially when you consider duplicated side effects. Since Scalars can be objects that are fairly complex aggregations that simultaneously hold (or appear to hold) multiple different values at once, this doesn't seem like a strong argument. But, to extract those alternative values from an object, you do something special to it, like call a method. Whenever you evaluate the object as a scalar, you get a single value back. Quite probably a reference to something much more elaborate, but a single value none the less. When you do a C, C is only called once. And what happens if you attempt to evaluate a junction in a non-boolean context? I dunno, which context are you concerned about? $a = any(2,3,4); $b = ? $a; # boolean context, $b == true $n = $a + 3; # numeric context, $n == any(5,6,7) $s = $a ~ 'x'; # string context, $s == any('2s', '3s', '4s') @l = ($a); # list context, @l == (any(2,3,4)) It was basically a reiteration of my "iterated side effect" argument, which gets worse if you do: @l = (any(1,2,3),any(4,5,6),any(7,8,9),any(10,11,12),any(13,14,15)); say @l.join(' '); I believe this generates 243 lines of text. IMO, this is not desirable. However, if the majority of people out there are fine with this behavior, I'll let it rest. I also have not seen any good way to avoid the situation. It's now been established that one can do a C<.isa("Junction")> to determine that what we have is, indeed, a junction. However, once that happens, your options are basically to either live with it, or throw an exception. If you're given 'cat'|'dog', there's no way to extract 'cat' and or 'dog', unless you happened to be expecting 'cat' and 'dog', and test for them explicitly. For clarification, is the type of 3|'four' == Junction|int|str? And I've yet to receive a good answer for what C<3/any(0,1)> does to $!. -- Rod Adams
Re: Fun with junctions (was Sets vs Junctions)
Patrick R. Michaud wrote: On Sat, Feb 12, 2005 at 01:18:53PM -0600, Rod Adams wrote: My issue is less that lists and sets are radically different. It is much more a matter of Junctions and Scalars are radically different. Getting me to accept that a Scalar holds several different values at once is a hard sell. Especially when you consider duplicated side effects. Since Scalars can be objects that are fairly complex aggregations that simultaneously hold (or appear to hold) multiple different values at once, this doesn't seem like a strong argument. But, to extract those alternative values from an object, you do something special to it, like call a method. Whenever you evaluate the object as a scalar, you get a single value back. Quite probably a reference to something much more elaborate, but a single value none the less. When you do a C, C is only called once. s/object/Junction/g above doesn't give me much grief. Extracting values from a Junction is also done by calling methods or functions. None of which has been mentioned or defined, so I was forced to assume they didn't exist. Of course, if we go this route, we are now saying that the return type signature of a sub is defined by an instance of class Junction. And what happens if you attempt to evaluate a junction in a non-boolean context? I dunno, which context are you concerned about? [...] It was basically a reiteration of my "iterated side effect" argument, which gets worse if you do: @l = (any(1,2,3),any(4,5,6),any(7,8,9),any(10,11,12),any(13,14,15)); say @l.join(' '); I'm not so sure it gets "worse" here -- @l.join(' ') gets evaluated first, and C is called only once because none of its parameters are a junction. In this case C is going to return a junction of strings. Similarly, as Scott Duff pointed out, C will be called only once, since the arguments to C are passed as part of a slurpy array and as such do not autothread. (No, I'm not entirely sure what would be output as a result. However, whatever it is, it should all be on one line, not 243 lines.) As I stated in a different message, my latest, fairly careful, interpretation of S09 rendered that autothreading and junctions were not directly related topics, even if I wrongly implied they were several posts ago. Thus the reference that slurpy lists cancel autothreading is not relevant to this issue. But if it makes the rest of the discussion go smoother, assume I've overwritten C with a non-slurpy version that otherwise does the same thing. I would still think that the above would print 243 times. Consider it this way: P5's C<"print"> returns true upon success. Thus, C would could also be considered a boolean function for "Is this printable with a linefeed after it?". So I could then write: @l = (any(1,2,3),any(4,5,6),any(7,8,9),any(10,11,12),any(13,14,15)); $x = say @l.join(' ')); Given the rest of Junction logic defined thus far, I would expect $x be a junction of 243 true/false values. I also have not seen any good way to avoid the situation. It's now been established that one can do a C<.isa("Junction")> to determine that what we have is, indeed, a junction. However, once that happens, your options are basically to either live with it, or throw an exception. If you're given 'cat'|'dog', there's no way to extract 'cat' and or 'dog', unless you happened to be expecting 'cat' and 'dog', and test for them explicitly. Umm, what's wrong with...? $l = 'cat'|'dog'|'mouse'; @extract = $l.values(); # ('cat', 'dog', 'mouse') The fact that it didn't exist until now. Does this mean we can do: @l = (any(qw/a b c d/) eq any(qw/c d e f/)).values(); and get @l == ('c','d')? For clarification, is the type of 3|'four' == Junction|int|str? I would guess the type of 3|'four' to be int|str, which is also a Junction, but don't hold me to that. But if you go with the Junction is a Class argument from above, I would expect the type would have to be Junction, and then one could query the Junction object as to what types it can mimic. Of course, we could have Junction do some magic, and have each instance create an anonymous subclass that is also ISA whatever types of values happen to be in it at the time. Which seems fairly heavyweight for something so integrated into the language. Will I be able to create variables that can hold ints, but _not_ junctions of ints? In other words, is: my int $x = 3|4; legal? How do I make it illegal, so as to protect myself from duplicated side effects which may be disastrous in application X? If the above is illegal, how do a declare a variable
Re: Fun with junctions (was Sets vs Junctions)
reiterate my autothreading concerns above. And in these, you still have to do something completely different to determine what the factors are. Sometimes a short loop is a good thing. btw, in my set notation, you get: @bar * {is_factor($^a, $foo)} -- Rod Adams
Re: Fun with junctions (was Sets vs Junctions)
Patrick R. Michaud wrote: Rod Adams wrote: I would argue that this sort of relational comparison is of limited usefulness. Well, except junctions hold more information than the simple comparisons I've given here. For example, a junction can have a value like: $x = ($a & $b) ^ ($c & $d) which is true only if $a and $b are true or $c and $d are true but not both. That's why I allowed for virtual sets, defined by a closure. Invariably, the next question that will nearly always be asked is "_Which_ values worked / didn't work?". If you're wanting to know *which* values worked, we still have C -- we don't need a special set notation for it, or to worry about junctions. Of course we'll always have C. But this is Perl, and I want YAWTDI. After all, another way to test membership was just added, whereas before you pretty much just had C. and((2,3,4) ?<= 3) btw, I like and()/or() over all()/any() because it makes it very clear we are establishing a boolean context. To me the fact that we're using <= establishes that we're interested in a boolean result; I don't need "and/or" to indicate that. Using "and" to mean "all" doesn't quite work for me, as I somehow think of "and" as a two-argument operation. That's a minor quibble, and I could go either way. [intersection] #foo * #bar # and we even know which ones! [containment] #foo <= #bar [non-intersection] !(#foo * #bar) Somehow overloading C<*> to mean "intersection" just doesn't work for me here. I'd have to think about it. I saw a reference to a flavor of Pascal that used it that way. C might be more in line with the math notation for it, but somehow I doubt that would make you feel better. Ultimately I don't think I agree with the notion that sets and lists are so different, or that sets deserve/require their own sigil. My issue is less that lists and sets are radically different. It is much more a matter of Junctions and Scalars are radically different. Getting me to accept that a Scalar holds several different values at once is a hard sell. Especially when you consider duplicated side effects. And what happens if you attempt to evaluate a junction in a non-boolean context? -- Rod Adams
Re: Fun with junctions (was Sets vs Junctions)
Damian Conway wrote: Patrick R. Michaud wrote: Ultimately I don't think I agree with the notion that sets and lists are so different, or that sets deserve/require their own sigil. Sets shouldn't have a sigil anyway, whether they're qualitatively different from lists or not. A set is a *value* (like an integer, or a string, or a list). A set is not a *container* (like an scalar or an array). And only containers get sigils in Perl. Yet you're wanting to store something which holds different values (a junction) in a scalar field. I could see holding an enumerated set in an array, without any trouble at all. But junctions can be more than an enumeration of elements. To steal Patrick's example from before: $x = ($a & $b) ^ ($c & $d) Which cannot be held in an array. So my argument here is that none of the existing containers are suitable for holding a set/junction. Scalars are meant to hold a single value. Junctions can hold several. Arrays can hold many different values, but cannot store the interrelationship between then, as in the example above. Hashes suffer the same problems as Arrays. So my proposal was to create a new container, Sets, to store them in. I included the ability to store enumerated values, as well as create more complex logic via closures. I was also attempting to add a bit of sanity to the semantics, by rephrasing things into something the average programmer would be able to parse. Given the numerous corrections to how one junction or another was parsed, I concluded that the exact semantics were becoming too subtle. I also find the following incredibly disturbing: >perl6 -e "$x = 'cat'|'dog'; say $x;" dog cat Getting iterated executions of a statement without explicitly iterating it bothers me greatly. I work heavily in databases, where updating or inserting twice with one call can be fatal to data consistency. So, if we are not having Sets, how exactly does one tell if what they are holding is a single value scalar, or a multi-value junction? Can a junction hold values of completely different types, or just different values of the same type? If evaluation of one value of a junction causes an error, is $! now a junction as well? -- Rod Adams
Re: Fun with junctions (was Sets vs Junctions)
Damian Conway wrote: Rod Adams wrote: I also find the following incredibly disturbing: >perl6 -e "$x = 'cat'|'dog'; say $x;" dog cat That would be disturbing if that's what happened. C is just a shorthand for C. So saying a junction is the same as printing it, which is a run-time error. So we have a restriction that Junctions cannot be outputted. What qualifies as output? Clearly C and its derivatives are output. What about a DBI call? Hmm. I guess it does ultimately resolve into a socket write, so it would be trapped there. However, what if what you're calling a non-Perl Parrot based function? Do we disable junctions from playing with non-PurePerl functions? Or do we autothread over them? How do we tell if a non-Perl function outputs to determine if we should be able to autothread into them or not? Out of curiosity, was the "Junctions can't be outputted" error documented somewhere prior to now? -- Rod Adams
Containers vs Objects.
In my recent unsuccessful attempt to convert junctions into sets with their own container, perhaps the strongest argument against could be paraphrased as follows: Everything about junctions or sets can be represented fully as an object, and objects are nicely stored in scalars, because it's simply one instance of a given class, in this case C. My question comes down to: so what makes Arrays and Hashes so special? As many pure-OO languages demonstrate, both can be fully represented as an object, and objects belong in Scalars. The obvious statement I expect to here is "Perl's always had Arrays and Hashes". While I'm not sure if they were there for Perl 1.0 (I started w/ Perl 4.xx), I do know that they certainly predate P5's objects and references. Therefore, there was no other way to create an array or hash. That is no longer the case. In P6, we've even gone so far as to say that you can access an element in an array ref with C<$ref[1]>. I'm fairly sure you can call all the methods of the Array class on the $ref, letting you do C<$ref.pop> and all the other fun things we do with arrays. Similar things hold for hashes. So I'm interested in hearing what pushes Arrays and Hashes over the edge for needing their own container and sigil, whereas Junctions/Sets do not. -- Rod Adams
Re: Fun with junctions (was Sets vs Junctions)
Damian Conway wrote: >Rod Adams wrote: > >> However, what if what you're calling a non-Perl Parrot based function? >> Do we disable junctions from playing with non-PurePerl functions? Or do >> we autothread over them? How do we tell if a non-Perl function outputs >> to determine if we should be able to autothread into them or not? > >The non-outputting happens at the output operation, which is *always* in >Parrot (at some level) and presumably is dealt with there. Certainly all Perl code is Parrot code, at some level. However, I think this is more Patrick's problem than Dan's, and that Patrick is going to need some guideince from I see it this way: When perl sees a function call, and one of the arguments is a junction, there are three basic options: 1) If the junction is wrapped up in some larger container, like a slurpy list, pass it on as is. 2) If the function in question is an "outputing" one, throw an exception. 3) autothread over the function. Consider the following: $x = 3|4; $y = fun($x); sub fun ($x) { warn "enter: fun($x)\n" if $DEBUG; $x + 1; } Which option from above is in effect? I do not think I left any room for the junction to be enclosed in a larger container, so option #1 is out. That leaves #2 and #3. If we autothread, the C only gets a regular scalar, and is happy, so we could get the dreaded repeated outputs. If we throw and exception, then we have the case that when debugging is turned off (normal case), there is no output at all, and we now have a very confused library user, wondering why this simple math function is complaining about outputting a junction. So is there a runtime internal flag, saying "I'm in the middle of autothreading a junction, if I happen across anything wanting to generate output, throw an exception."? That would certainly solve the pure Perl problem. But it starts to break down at the Parrot level. Now consider the case that above fun() was written in Python, and imported into the perl-space. Constrast that to the CPAN author who refactors a perceived slow part of their module into PIR or even into C, and binding it into Parrot via neo-XS. (I don't follow p6i enough to remember what they call it. Certainly it's better than "neo-XS"). How does the "runtime flag" work in these cases? Does Parrot now have to mark all the subs that _might_ perform some type of output as such, regardless of where that sub came from? If so, has Dan signed off on this? If not, how does Patrick resolve whether to autothread or raise exception? -- Rod Adams
Re: Containers vs Objects.
At 01:04 PM 2/15/2005 -0800, chromatic wrote: On Tue, 2005-02-15 at 14:26 -0600, Rod Adams wrote: > So I'm interested in hearing what pushes Arrays and Hashes over the edge > for needing their own container and sigil, whereas Junctions/Sets do not. Perl isn't a "pure" object-oriented language. No argument there. Which is why I was interested effectively the argument that "Junctions/Sets are Objects, and don't need their own container/sigil" was considered so compelling. -- Rod Adams
Re: Fun with junctions (was Sets vs Junctions)
Larry Wall wrote: Or perhaps the problem isn't returning junctions per se, but storing them into a variable that the user is thinking of as a simple scalar value. That was the largest, perhaps only, reason I made my "Sets vs Junctions" post. Although my solution to the issue was different from yours in almost every respect. You put limits on unsuspectedly storing a junction in a scalar. I made a new place to put them. -- Rod Adams
Re: Containers vs Objects.
chromatic wrote: So I'm interested in hearing what pushes Arrays and Hashes over the edge for needing their own container and sigil, whereas Junctions/Sets do not. Perl isn't a "pure" object-oriented language. Rephrasing my question: What characteristics would _any_ new structure or class have to have to merit becoming a first class container with it's own sigil, rather than being just another class? Or is Perl close enough to "pure" object-oriented these days, where only grandfathered classes make the cut? As a separate question, is there a relatively easy way to create a user-defined class with it's own sigil? (w/o having to modify half the parse rules). -- Rod Adams
Re: Fun with junctions (was Sets vs Junctions)
Patrick R. Michaud wrote: On Tue, Feb 15, 2005 at 03:07:53PM -0600, Rod Adams wrote: I see it this way: When perl sees a function call, and one of the arguments is a junction, there are three basic options: 1) If the junction is wrapped up in some larger container, like a slurpy list, pass it on as is. 2) If the function in question is an "outputing" one, throw an exception. 3) autothread over the function. Consider the following: $x = 3|4; $y = fun($x); sub fun ($x) { warn "enter: fun($x)\n" if $DEBUG; $x + 1; } Which option from above is in effect? I do not think I left any room for the junction to be enclosed in a larger container, so option #1 is out. That leaves #2 and #3. If we autothread, the C only gets a regular scalar, and is happy, so we could get the dreaded repeated outputs. As you've written things above, C is autothreaded (your option #3), and we'll see two C output lines if $DEBUG is set. Whether or not the repeated outputs are "dreaded" is a matter of perspective. Since the caller has chosen to pass a junction to C, the caller shouldn't be overtly surprised when C is autothreaded, or that it generates multiple output lines. In fact, I'd be concerned if it didn't. The case of Damian's response in a prior message: Rod Adams wrote: I also find the following incredibly disturbing: >perl6 -e "$x = 'cat'|'dog'; say $x;" dog cat That would be disturbing if that's what happened. C is just a shorthand for C. So saying a junction is the same as printing it, which is a run-time error. Could easily be achieved with a single layer of encapsulation? perl6 -e "$x = 'cat'|'dog'; say1 $x; sub say1 ($x) {say $x}" Or is the consensus that that's somehow not disturbing, and direct calls are disturbing. If what you're saying is true, then feeding a junction into DBI for a "insert" statement, since the output proper is encapsulated, would create multiple new records in the database? I'm back to being very disturbed. If so, has Dan signed off on this? If not, how does Patrick resolve whether to autothread or raise exception? Well, the ultimate answer is that both Dan and Patrick (and others) will negotiate the exact interface when we get to that point, and that we don't seem to be too concerned about it at the moment. (It could just be that we're both burying our heads in the sand hoping it'll be magically "solved" by the other. :-) Actually, using the semantics you've outlined above, there is no implementation problem. However, I disagree that those semantics are desirable. OTOH, what happens with...? sub nofun($x is rw) { $x += 2; } $y = 3 | 4; nofun($y); Do we need to change the semantics of what happens with autothreading to: method autothread (&func, $junction) { my $result; my $value; for $junction.values -> $value { my $temp = $value; func($temp); $result |= $temp; } $result; } -- Rod Adams
Junction Values
Okay, so we've established that: $x = any(3,4,5); @l = $x.values.sort; Leaves us with @l == (3,4,5), and that makes a fair amount of sense. What do the following evaluate to: @l1 = all(3,4,5).values.sort; @l2 = one(3,4,5).values.sort; @l3 = none(3,4,5).values.sort; @l4 = any(all(1,2),all(3,4)).values.sort; If C<.values> doesn't it cut it for these cases, what other forms of introspection are we going to allow on junctions, to determine what they are? On a slightly different topic, do the following equivalences work: any($a, $a) == $a any($a,$a,$b) == any($a,$b) any(any($a,$b),any($c,$d)) == any($a,$b,$c,$d) all($a, $a) == $a all($a,$a,$b) == all($a,$b) all(all($a,$b),any($c,$d)) == all($a,$b,$c,$d) none($a, $a) == undef none($a,$a,$b) == none($a,$b) none(none($a,$b),none($c,$d)) == none($a,$b,$c,$d) one($a, $a) == false one($a,$a,$b) == ($a == $b ?? undef :: $b) -- Rod Adams
Re: Junction Values
Damian Conway wrote: .values tells you what raw values are inside the junction. The other kind of introspection that's desirable is: "what raw values can *match* this junction". There would probably be a .states method for that. To see the difference between the two, consider: my $ideal_partner = all( any(Âtall dark richÂ), any(Ârich old frailÂ), any(ÂAustralian richÂ), ); $ideal_partner.values would return the three distinct values in the junction: ( any(Âtall dark richÂ), any(Ârich old frailÂ), any(ÂAustralian richÂ), ); But $ideal_partner.states would return only those non-junctive values that (smart-)match the junction. Namely, "rich". One would need a method of determining whether the C<.values> are in an any/all/none/one relationship. Trivial, but necessary. That and C<.values> are likely enough introspection. Leave the C<.state> for CPAN to solve. On a slightly different topic, do the following equivalences work: (I will assume in all my answers that $a, $b, $c, $d have different values, except where it doesn't matter either way). all($a,$a,$b) == all($a,$b) False. The autothreading makes that: all( $a==$a, $a==$b, $b==$b, $b==$a) and they're not (in general) all true. I knew I was typing this all wrong. Whipping out math symbols, replace the == with â, or identical to. In other words, I was not asking how C< if all($a,$a,$b) == all($a,$b) {...} > evaluated, but instead if if all($a,$a,$b) {...} if all($a,$b) {...} would both evaluate the same. And I was making no assumptions about the values of $a .. $d. all(all($a,$b),any($c,$d)) == all($a,$b,$c,$d) False. Because all($a,$b) != all($a,$b,$c,$d) Should have been all(all($a,$b), all($c,$d)) â all($a,$b,$c,$d) Sorry for any confusion. It's just a real pain to type chars that are not bound on your keyboard. As for the undef's, I didn't know what else to call the empty junctive. -- Rod Adams
Re: Junction Values
Patrick R. Michaud wrote: none(none($a,$b),none($c,$d)) == none($a,$b,$c,$d) True. H... -> none(none($a,$b) == none($a,$b,$c,$d), none($c,$d) == none($a,$b,$c,$d)) -> none(none($a == none($a,$b,$c,$d), $b == none($a,$b,$c,$d)), none($c == none($a,$b,$c,$d), $d == none($a,$b,$c,$d))) -> none(none(none($a==$a, $a==$b, $a==$c, $a==$d), none($b==$a, $b==$b, $b==$c, $b==$d)), none(none($c==$a, $c==$b, $c==$c, $c==$d), none($d==$a, $d==$b, $d==$c, $d==$d))) -> none(none(none(1, 0, 0, 0), none(0, 1, 0, 0)), none(none(0, 0, 1, 0), none(0, 0, 0, 1))) -> none(none(0, 0), none(0, 0)) -> none(1,1) -> false Ummm, what am I missing? To state it another way... we can show that none($a,$b) == none($a, $b, $c, $d) is true, so none( none($a,$b), none($c,$d) ) == none($a, $b, $c, $d) is equivalent to none( none($a,$b) == none($a, $b, $c, $d), none($c,$d) == none($a, $b, $c, $d)) which is none(1, 1), or false. Did I autothread wrongly here? No, upon closer looking, you're right that it should both evaluate false, and that they are not equivalent in what I meant to be asking. none(none($a,$b),none($c,$d)) ? all(any($a,$b),any($c,$d)) Should work, though. Not that it helps simplify matters at all. In essence, what I'm doing is attempting to create a set of rules whereby one can simplify a junction, by removing the nestedness of it, or removing terms outright. In the process, I'm making sure that I understand what they mean. -- Rod Adams
Re: Containers vs Objects.
Larry Wall wrote: But as far as English is concerned, sets are just objects that have a singular outside and a (potentially) plural inside, much like almost any other object. At least, that's how concrete sets work. Hmm. I would argue that most of the time, when English Speakers use sets quite commonly in their speak, and often refer to them as lists (e.g. Shopping Lists). In fact, when expressing any list, we go out of our way to explicitly give them an order or ranking. Not to mention people do think in terms of sets. Back to the shopping list, you have the set of things on your list (#list), and the set of things in your cart (#cart), as well as the things in the store (#store). What can you cross off your list? #list x #cart What's left to buy? #list - #cart What's not available? #list - #store What did you buy that wasn't asked for? #cart - #list Add to this the not infrequent use of the phrase "You listed ___ twice." in response to hearing a list, thus implying something more set-ish about it than an array gets. Or the frequency with which one gives six or more responses to the question "What are your top 5 ?" I have little ability to translate hashes into English, beyond "How many cans of ___ are in the cupboard?" So in terms of frequency of use in the English Language, I'd rank things in the following order: 1) Scalars 2) Sets 3) Arrays 4) Hashes As for Perl Speakers, I would argue that a high percentage of the time someone says C< for @list {...} >, they really don't care for which order the elements are executed in, just that they are. Creating a hash where all the values are 1, just to get the set like features of the keys, is a fairly common Perl idiom. As Computer Science Speakers, Sets are a very fundamental data structure. Okay, not as fundamental as Arrays. But easily more so than Hashes. Programmers tend not to speak in terms of Sets very often, because their languages don't support them. Junctions, on the other hand, almost never come up in English, except as a Set. Where do you see sentences which have a word which means two other words _at_once_, and the listener is supposed to understand all of the meanings? Double entendres come close, but there are two main drawbacks: 1) only a limited set of words can be used in this case, and each of them has a very limited number of values it can possess. Not any noun taking on the value of any two or more other nouns at once. 2) it is almost never in question that only one meaning was meant, and the other meaning was merely a cover, to prevent a faux-pas. -- Rod Adams
Re: Junction Values
Patrick R. Michaud wrote: On Wed, Feb 16, 2005 at 06:04:37PM +, Nigel Sandever wrote: If the hyper operator returned one boolean result for each comparison it made, and if a list of boolean values in a boolean context collapsed to a count of the trues/1s it contained, I think those would work. Part of the problem is that we don't have a "list of boolean values" that is somehow distinguishable from "list of values". (And a list evaluated in boolean context is true if the list is non-empty.) If we create a "list of boolean values" type, it effectively becomes a junction. :-) What if we instead redefine any/all/one/none to be functions (and/or list methods) that take a list, evaluates each element in boolean context, and returns boolean? Therefore, Nigels's examples become: if any( $x »==« @list) { ... } if none($x »==« @list) { ... } if all( $x »==« @list) { ... } if one( $x »==« @list) { ... } Then case that I see happening most often will then be: if any($x »==« (1,2,10,100,200,1000,2000)) { ... } I'll also throw in the argue that anything much more complex than this definitely falls into the category of "edge case", and is of dubious utility, and IMHO, a lot of danger. It occurred to me that junctions felt a lot like typeglobs. Very powerful thing, that little *. But also something that experienced programmers tell inexperienced ones something like "Don't mess with them unless you really understand them." Then throw in that most programmers use a heavy dose of lexicals, which aren't typeglobable. In the end, you are left with only one useful idiom left: *NewFunc = sub {...}; Which will usually appears inside an AUTOLOAD. (yes, I'm sure that Damian and some others on this list can create exceptionally cool use of typeglobs, in ways that would warp our minds, but I'm talking overall utility). How does this relate to junctions? All I think anyone ever *asked* for out of a junction was an easier way to write: if ($x==$a or $x==$b or $x==$c or $x==$d) { ... } The rest of the invention feels like "Magic", and is something the experienced will tell the inexperienced not to mess with until they really understand the consequences of using them. And even then, few of the experienced will make more use of it than the simple case. -- Rod Adams
Re: Junction Values
Larry Wall wrote: That, and we'd like a novice to be able to write given $x { when 1 | 2 | 3 {...} when 4 | 5 | 6 {...} } Or just change C to accept a list of things to compare against, followed by a coderef. -- Rod Adams
Re: Junction Values
Brent 'Dax' Royal-Gordon wrote: Rod Adams <[EMAIL PROTECTED]> wrote: Larry Wall wrote: That, and we'd like a novice to be able to write given $x { when 1 | 2 | 3 {...} when 4 | 5 | 6 {...} } Or just change C to accept a list of things to compare against, followed by a coderef. And change if, unless, while and until to do the same thing. Actually, upon further investigation, I believe we get this all of this without junctions. According to S03, "The scalar comma |,| now constructs a list reference of its operands." Then S04 mentions that C< $scalar ~~ @array > is true if $scalar is in @array. Since C< given ... when > uses smart matching for it's evaluation, one should be able to write the above as: given $x { when 1, 2, 3 {...} # at worst, this is: when (1,2,3) {...} when 4, 5, 6 {...} } The simple if is: if $x ~~ (1,2,3,4) {...} # parens needed here since , is lower than ~~ in precedence. Same for unless/while/until. And all of this from the entirely useful C< ~~ >. The S04 code describing @Array ~~ $Scalar (for Num/Str) uses junctions, but I'd argue a better implementation would be a short circuiting C< for > loop, even if junctions exist. It's just plain faster that way. So what I see now for utility of junctions is thus: - Common cases which C< ~~ > appears to handle for us suitably well. - Edge cases which, IMHO, do not merit the huffman level of several single character operators. All of which can be accomplished without the use of junctions, though not as gracefully. I see no need for junctions in core. And lose the ability to say: when none(1, 2, 3) { ... } when 1 ^ 2 ^ 3 { ... }# More useful with classes, regexen, etc. when 1 & 2 & 3 { ... }# Likewise All so that a newbie doesn't confuzzle himself. You can always write your switch statements the Perl 5 way. Or you could write: when ({$^a ~~ /1/ && $^a ~~ /2/ && $^a ~~/3/}) {...} And the like. Look up what C< $scalar ~~ $coderef > does if you're not convinced. (side question: what is the proper syntax for using a closure as the evaluation expression in a C< when > statement?) hmm, since the $_ is set, you could likely get away with: when ({/1/ && /2/ && /3/}) {...} in the case of RE's. Personally, I'd rather have a chain saw than a nail trimmer, even if I'm less likely to hurt myself with the nail trimmer. And it looks like we'll have a warning or stricture to keep newbies from chopping their legs off anyway. I can understand your sentiments here, but I'd be a lot more sympathetic to your cause if the alternative ways of accomplishing these things were actually difficult. I think it's been demonstrated that any of the junction evaluations could be done with a call to C< grep >, with numerous other ways to perform them as well. -- Rod Adams
Re: Junction Values
Larry Wall wrote: On Thu, Feb 17, 2005 at 02:18:55AM -0600, Rod Adams wrote: : The simple if is: : : if $x ~~ (1,2,3,4) {...} # parens needed here since , is lower than ~~ : in precedence. That is asking if $x is a list containing 1,2,3,4. Quoting S04: $_ $xType of Match ImpliedMatching Code == = == Array Array arrays are identical match if $_ »~~« $x Array any(list) list intersectionmatch if any(@$_) ~~ any(list) Array Rule array grep match if any(@$_) ~~ /$x/ Array Num array contains numbermatch if any($_) == $x Array Str array contains stringmatch if any($_) eq $x And since there are no tell tell *'s on these saying that they are _not_ reversible, I must assume they _are_. In C< if $x ~~ (1,2,3,4) {...} >, if $x is type Num or Str, then I see no way of reconciling your statement above. : Same for unless/while/until. And all of this from the entirely useful C< : ~~ >. The S04 code describing @Array ~~ $Scalar (for Num/Str) uses : junctions, but I'd argue a better implementation would be a short : circuiting C< for > loop, even if junctions exist. It's just plain : faster that way. Junctions can short circuit when they feel like it, and might in some cases do a better job of picking the evaluation order than a human. I was afraid someone was going to say that. And I now must convert my reservations about junction autothreading from "very disturbing" to "you've got to be kidding". According to Patrick, and since no one has corrected him, I will assume he is right, perl6 -e "say1 'cat'|'dog'; sub say1 ($x) {say $x}" Should output "cat\ndog\n" or "dog\ncat\n". Now, if we allow Junctions to short circuit, and since there is no fixed order of values in a junction, we could get any of "cat\ndog\n", "dog\ncat\n", "cat\n", or "dog\n". What's that get us? non-deterministic output! I could handle non-deterministic *order* of output, because by the simple fact that you were using a junction, you didn't care about order. Non-deterministic output! how fun! Not to mention it contradicts S09: "... 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." Now there is some wiggle room in there for short circuiting, but not very much. : So what I see now for utility of junctions is thus: : : - Common cases which C< ~~ > appears to handle for us suitably well. Only if we make lists second-class citizens. The need for junctions first became evident when we found ourselves filling the ~~ tables with various sorts of weird non-symmetries. So what other semantic makes sense for: Str ~~ Array Num ~~ Array which would better appeal to your sense of symmetry? Besides, people were telling me that my Sets were not needed, because they could be rendered with Arrays and Hashes. I fail to see how junctions are that different. : - Edge cases which, IMHO, do not merit the huffman level of several : single character operators. All of which can be accomplished without the : use of junctions, though not as gracefully. Grace is important. Even more important is mapping naturally to human linguistic structures, to the extent that it can be done unambiguously. In my experience, English tends not to superimpose several values on a given noun at once. : I see no need for junctions in core. I do, and I'm not likely to change my mind on this one. Sorry. I realized that fairly early on. The situation I'm in is that while I don't agree with all the design initiatives that come out here, it's been the case that the more I think about them, the more I like them. I always achieve at least a state of ambivalence or better about it. With Junctions, it's been the case that at first I thought they were useful and cool, but the more I think about them, the more I dislike them. I'll argue my case for a few more days, and if I haven't gotten anywhere by then, I'll likely give up. -- Rod Adams
Re: Junction Values
Brent 'Dax' Royal-Gordon wrote: Rod Adams <[EMAIL PROTECTED]> wrote: Larry Wall wrote: Junctions can short circuit when they feel like it, and might in some cases do a better job of picking the evaluation order than a human. I was afraid someone was going to say that. And I now must convert my reservations about junction autothreading from "very disturbing" to "you've got to be kidding". ... Not to mention it contradicts S09: "... 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." Now there is some wiggle room in there for short circuiting, but not very much. The "wiggle room" is that the junction knows when it's being asked to collapse into a Boolean, and can know if there's no possible way the function it's running will have side effects. (That's why we're declaring ties now. There may be cases where we can't know for sure if there will be side effects or not--Halting Problem stuff--but we can make sure the junction optimizer is conservative. The Halting Problem becomes a lot easier if you ask whether a program *might* halt instead of whether it *will*.) In general, it seems to simply be an amazingly bad idea to autothread a function with side effects. In fact, I'd recommend that we warn if a side effect occurs during autothreading. Besides, people were telling me that my Sets were not needed, because they could be rendered with Arrays and Hashes. I fail to see how junctions are that different. Junctions are intended to be used mainly within conditionals and other statements; If the set of these "other statements" is limited, consider creating a Junction class (which needs a "use Junction;" to activate), which overloads the various comparison operators for when a Junction is involved, and defines any/all/none/one as constructors? Throw in some overloading or bindings for |/^/&, and it looks like you get everything your asking for. Having a method evaluate: C< 5 == any(4,5,6) > means that the interpreter doesn't need to autothread. This also makes it where only functions that were explicitly designed to use Junctions, or ones which didn't declare their signature, and thus are making no assumptions about what they are given, will perform the Junctive evaluations. This way, you get all the happy functionality, at the cost of typing "use Junction;", and I get loads of protection against the evil side of autothreading. Doing Junctions this way also makes the them extensible. If someone figures out what a "not" junction is, they can add it in later. And people like me can't complain about what the module is doing to the language, because "all's fair if you predeclare" would be in effect. I think junctions are important at the statement level because they help make similar things look similar. Consider these two statements: if($foo == $bar) { .. } if(grep { $foo == $_ } $bar, $baz) { ... } What makes these two statements so fundamentally different from each other that they should be expressed in ways that *look* so different? You mean besides the shift in plurality? A shift in plurality in English forces you to modify a hefty portion of your sentence to accommodate it. At a minimum, you change your verb, in this case the C< == >. Shifting plurality in programming languages also incurs changes to the code around it. : - Edge cases which, IMHO, do not merit the huffman level of several : single character operators. All of which can be accomplished without the : use of junctions, though not as gracefully. Grace is important. Even more important is mapping naturally to human linguistic structures, to the extent that it can be done unambiguously. In my experience, English tends not to superimpose several values on a given noun at once. No, but nor does it have a concept quite like a variable. Which significantly weakens the "mapping naturally to human linguistic structures" argument, IMO. Junctions are equivalent to the English sentence "Get eggs, bacon, and toast from the store". (In Perl, that'd be something like C<< $store->get("eggs" & "bacon" & "toast") >>.) Or just have C< get() > take a list, and it's: $store->get(<>); # is that the latest use of <<>>? It's just a bit of orthogonality that allows you to give "eggs, bacon, and toast" a name and use it later. @shopping list = <>; gives them a name you can use later, as well. -- Rod Adams
Re: Junction Values
Larry Wall wrote: The need for junctions first became evident when we found ourselves filling the ~~ tables with various sorts of weird non-symmetries. ~~ can easily be called the "DWIM compare" operator. It even looks like you're waving your hands, asking for some strange voodoo to happen. It can also be thought of as "Here! take these two things, do something with them, and tell me how it went". So it's magic central. And magic is invariably a messy thing to implement. And once the concept is out there, is makes sense to have practically every combination of types do _something_ useful if fed to ~~. Which makes it where ~~ is likely destined to be one of the most overloaded operators in the history of computing. So be it. It's amazingly useful. It also takes a monstrous amount of the Perl 6 DWIMery and puts it all in one place. Not to mention, you've already defined P6 to be good at this multi-sub/method game, so take advantage of it. It's not like this table will be represented all in one function (at least I hope not) -- Rod Adams
Re: Junction Values
Luke Palmer wrote: Rod Adams writes: Junctions are intended to be used mainly within conditionals and other statements; If the set of these "other statements" is limited, consider creating a Junction class (which needs a "use Junction;" to activate), which overloads the various comparison operators for when a Junction is involved, and defines any/all/none/one as constructors? Throw in some overloading or bindings for |/^/&, and it looks like you get everything your asking for. Having a method evaluate: C< 5 == any(4,5,6) > means that the interpreter doesn't need to autothread. This also makes it where only functions that were explicitly designed to use Junctions, or ones which didn't declare their signature, and thus are making no assumptions about what they are given, will perform the Junctive evaluations. Okay, I think your proposal is thinning. I'm trying to salvage what I can, since people seem to be rejecting everything I offer. Perl is a dynamically typed language. I have no doubts that people will continue to ignore the type system even though it's there. I probably will. So will I. Let me demonstrate something: sub is_prime($x) { my @primes; for 2..sqrt($x) { if $_ % none(@primes) == 0 { push @primes, $_; } } return 1 if $x % none(@primes) == 0; } Run through your mind how this would be done with a junction in $x. Particularly focus on: 2..sqrt($x) What the hell does that mean? Do you get a junction of lists out? Or does sqrt die because it's not expecting a junction? What on earth does C< for (2..sqrt(3|5)) {...} > mean in the current state of junctions? But as written, yes, sqrt() would likely throw an exception under my proposal. When I say: if is_prime(any(@stuff)) {...} I expect to run the codeblock if any of my stuff is prime. Instead I get an error, always. I could always do this: if @stuff.grep:{ is_prime($_) } {...} Should also be able to overload Junction ~~ CodeRef to make this work: if any(@stuff) ~~ &is_prime {...} In this manner, you are explicitly controlling when and how the autothreading happens. There is no way for is_prime to slurp up the junction and pass it on in this case. However, in the current scheme, if is_prime() is written to accept a slurpy list of parameters (either by design, or just a habit from the P5 days), we can have: sub is_prime { my @primes; for 2..sqrt(@_[0]) { if $_ % none(@primes) == 0 { push @primes, $_; } } return 1 if $x % none(@primes) == 0; } Pushing the autothreading directly onto the C< for (2..sqrt(3|5)) {...} >, which as you pointed out earlier, is almost definitely _not_ what was wanted, whatever it means. (btw, My current analysis says it will stop at the lowest value in the junction.) I view it as a definite plus to make the autothreading explicit. I doesn't need it to be ugly, just present. In fact, that's all I need to shut up on this whole issue. Something that says: "autothreading into functions only happens when you slap (whatever) in there." I can live with auto-autothreading over operators (I'd rather not, though). But calling into a function needs something stronger. Yes, operators are functions, too, but if you're fancy enough to be writing you're own operators, you're fancy enough to take junctions into account. Something like: if is_prime(Âany(@stuff)Â) {...} Would more than suffice. It says that you're not attempting to pass the junction, but instead doing something in parallel, which is what the hyper operators are all about, anyways. It's been the side effects of autothreading that has been my big hold up. If you make it happen explicitly, it's just another looping construct ( a very odd one, but one nonetheless ). If it happens implicitly, it's way too magical and dangerous for my tastes. Give me that, and I'll probably start liking Junctions. I've never argued that they weren't powerful. But the whole point of junctions is to get rid of obscure expressions like that. Brent makes a fantastic case here. The point is that when you say "makes no assumptions", you're giving the sub writers too much credit. I think a reasonable assumption (especially for these alledged "novices" you keep talking about) that these two code segments are equivalent: if $x == 2 {...} elsif $x == 3 {...} And: if $x == 2 {...} if $x == 3 {...} No matter what the value of $x. Yet in the presence of junctions, they are not. Also note that this is a practical example. I like the former, I know people who like the latter. It's a matter of style, and it's one that will bite you if you don't know about junctions. You get into this probl
Re: Junction Values
Jonathan Scott Duff wrote: On Fri, Feb 18, 2005 at 12:42:31PM -0600, Rod Adams wrote: No, but nor does it have a concept quite like a variable. Which significantly weakens the "mapping naturally to human linguistic structures" argument, IMO. Why exactly? It's just the variable-nature of variables that isn't exactly expressed linguistically, otherwise variables are just nouns really. And nouns either refer to single item, or a group of items as a whole. Not one item that behaves like a chameleon. When you say "The French", you are referring to the entire group of people that associate themselves with the country of France. Not all the people of France juxtaposed into one entity. If you want that, you say "A Frenchmen" or "One of the French", but even then you are referring to a single person, who happens to part of the group "The French". This last is a pure Set membership question. The same "The French" can be used as : "The French are invading!!". With a junction, you can build something that says "any group of people from France", "one person from France", "everyone from France", and even "not from France", but none of them embody the concept that we think of as "The French". If you were to have an embodiment of "The French" (as I proposed way back in "Sets vs Junctions"), it is fairly easy to then create all of the above junctions. Via the introspection that Junctions are being defined with, it's possible to get that back out, but not smoothly. So, linguistically, a noun is either a specific entity, or a group of things, taken as a whole. As Damian so emphatically stated earlier in this long and twisting thread, a Junction is not a group of things, lopped together. It is one single thing, that has several different values at once. In addition, it also has a boolean function (any/all/one/none), declaring how all these values relate when evaluated. The closest linguistic parallel to this I've see is the double entendre, which doesn't even come close. Sets and Junctions are two different things. They are related, but quite different, and should not be confused. Junctions are equivalent to the English sentence "Get eggs, bacon, and toast from the store". (In Perl, that'd be something like C<< $store->get("eggs" & "bacon" & "toast") >>.) Or just have C< get() > take a list, and it's: $store->get(<>); # is that the latest use of <<>>? It's just a bit of orthogonality that allows you to give "eggs, bacon, and toast" a name and use it later. shopping list = <>; gives them a name you can use later, as well. Except that you've introduced a definite ordering where one isn't needed. Yes, well, people don't get to use that argument on me after repeatedly saying that sets could be easily stored in arrays and/or hashes. I don't remember if you, personally said it, but it felt like a consensus vote from over here. One I don't really disagree with. Not to mention the definite ordering only matters if you process it in a way that it does. In attempts to better explain: $store->get("eggs" & "bacon" & "toast"); $store->get(<>); say two radically different things. The first statement says: "Go to the store and get Eggs. Go to the store and get Bacon. Go to the store and get Toast. Save the results of each trip separately, and then when someone asks how your trip (not trips) to the store went, you then see if all the results are the same." The second statement says: "Go to the store once. You have the following shopping list: Eggs, Bacon, Toast. Was your trip successful?" -- Rod Adams
Re: Junction Values
Ashley Winters wrote: On Fri, 18 Feb 2005 12:47:51 -0700, Luke Palmer <[EMAIL PROTECTED]> wrote: Run through your mind how this would be done with a junction in $x. Particularly focus on: 2..sqrt($x) What the hell does that mean? Do you get a junction of lists out? Or does sqrt die because it's not expecting a junction? sqrt() won't die; it gets threaded and returns a Junction, I would expect. It's the lack of an &*infix:<..>(Int, Junction) function which causes death In the context this question was posed, the proposal I was making, sqrt() would throw an exception. But that's likely not what this discussion is about. In the terms of junctions as defined, I expect that it would stop at the lowest value of $x greater than or equal to 4. Unless we start allowing junctive lists as well as junctive scalars... -- Rod Adams.
Re: Junction Values
Craig DeForest wrote: Hmmm... It seems that this way does lie madness -- there's a fundamental ambiguity between autothreading happening inside or outside the declared loop, and there's no "least surprising" way to implement it. Certainly inside the loop is the easiest and most natural to implement, but that acts strange from an API standpoint. Outside the loop works well from an API standpoint but introduces all sorts of weird cases that the implementation has to consider. I would think that my latest idea of turning off "autothreading" per se, and replacing it with an explicit "threading" call/operator, would solve this dilemma. The idea was specifically to have it where threading happened on function calls when a junction was surrounded by hyper operators. Otherwise, the junction is passed "as is". So we still get: if $x == 3|4|5|6 {...} would thread over infix:<==> without any funkiness, since we'll assume operators are well written, and can take junctions as parameters, same as: if is_prime(3|4|5|6) {...} Would pass the junction to is_prime, to do with as it pleases, including throwing an exception. However, if is_prime(»3|4|5|6«) {...} would thread over is_prime, and collate the results outside of call. These semantics also give us the ability to easily mix and match what we send to a function, so we can say: if funky_test(all(@A), »any(@B)«) {...} Basically I'm putting all the power of threading into the hands of the caller. I will further argue that C< »junction« > should not short circuit. It should do the simple brute force "try all values" approach, since the side effects are likely desired. Operators, which should be able to accept junctions as parameters, are encouraged to short circuit, since there are no side effects possible for the evaluation of that operator. By the time the operator gets called, it should have all the parameters it needs, and there are no more side effects to be had. As for C< .. >, I'd say that it should handle junctions being fed into it by throwing an exception. -- Rod Adams
Re: Junction Values
Brent 'Dax' Royal-Gordon wrote: Rod Adams <[EMAIL PROTECTED]> wrote: Luke Palmer wrote: 2..sqrt($x) What the hell does that mean? Do you get a junction of lists out? Or does sqrt die because it's not expecting a junction? What on earth does C< for (2..sqrt(3|5)) {...} > mean in the current state of junctions? In the current state of junctions, the autothreading is done at the level of the call to do_prime, so $x is never a junction. Actually, if one writes is_prime to have slurpy array passing a la Perl5, as I wrote in a different post, $x most certainly is a junction at this point. Although this does beg the question: If by default one can't assign a junction to a variable, does this apply only in cases with an assignment operator, or does it also happen on parameter passing? I've just reread Larry's post about normally disallowing storage of junctions in a lvalue. He covers the point about declaring parameters that are junctional, and the parameters are otherwise non-junctional. What is not clear here is whether or not the S09 talk about if a junction is inside another container (like a slurpy array), if it gets caught or not. The array itself is not a junction, but one or more of it's elements might be. So do we have to walk the entire reference tree if we are given a complex data type, looking for junctions? This is not an option, think no further than lazy lists to see why. So the other option is to have a runtime check, and as soon as a memory store containing a junction is encountered, then throw an exception. Even if this happens well after the parameter passing step. Hmm. Messy, but possible. Only under your notion of junctions as just another object with no autothreading until the operator level will $x ever be a junction. For the record, I've withdrawn that proposal. All I want now is for autothreading to be explicit. But if it somehow *did* become a junction, I would imagine something like this would happen: for (2 .. sqrt( 3 | 5 )) { ... } for (2 .. ( sqrt 3 | sqrt 5 )) { ... } for ( ( 2 .. sqrt 3 ) | ( 2 .. sqrt 5 ) ) { ... } for ( 2 .. sqrt 3 ) { ... } | for ( 2 .. sqrt 5 ) { ... }#notionally However, it's clear that the last step doesn't make a whole lot of sense, since C has no return value. Maybe C would be declared with a signature that didn't allow junctions at all. Or is it the case that C< .. > acts a bit like the old flip flop it used to be, and stop at the first true value it sees? AFAIK, the concept of Junctional Lists has not been created yet, so what else would it return? A list of junctions? all of which are ($x|$x) or ($x|undef)? However, in the current scheme, if is_prime() is written to accept a slurpy list of parameters (either by design, or just a habit from the P5 days), we can have: I will readily admit that the behavior of junctions in a slurpy subroutine call is suboptimal, and it might be a good idea to reexamine it. However, I will also point out that most newbie programmers probably won't use the @_ behavior, and likely won't be using slurpy parameters either, while more experienced programmers will know better. Except for the absolutely massive amount of Perl5 code out there that will be hastily translated by people who don't trust the Perl6 <-> Ponie interplay, and the flocks of Perl5 programmers coming over without learning all the new features of their upgraded language, you're probably right. -- Rod Adams
Re: Junction Values
Brent 'Dax' Royal-Gordon wrote: Rod Adams <[EMAIL PROTECTED]> wrote: if $x == 3|4|5|6 {...} would thread over infix:<==> without any funkiness, since we'll assume operators are well written, and can take junctions as parameters, same as: if is_prime(3|4|5|6) {...} Would pass the junction to is_prime, to do with as it pleases, including throwing an exception. However, if is_prime(»3|4|5|6«) {...} would thread over is_prime, and collate the results outside of call. So basically you're proposing that, rather than do one implicit loop that'll probably do what you want, the default should be to do an unknown number of implicit loops in somebody else's code, and you have to ask explicitly for the more sensible behavior. Somehow this doesn't strike me as an improvement. What I'm asking for is to be in control of how often I get the possible side effects of calling a function. If I make a call to a DBI method to go insert a record, I want exactly 0 (on error) or 1 (on success) records inserted into my database, _unless_ I told it do otherwise. Since a junction is a single item, it should produce a single effect _unless_ I tell it to expand the values and act like several items at once. Simply put, I want control over my side effects. As for whether passing the junction as a junction or passing the junction via autothreading should be the default: Junctions exists. I want to say "stay a junction" or "explode into pieces, go your separate ways, and then come back". In one case I'm doing nothing to the junction, in the other case I'm doing quite a bit. So it makes sense that the latter is something additional to the former. Taking into account how common that particular action might be, I chose to propose a rather short modification to it, that still clearly said something special was going on here. One could say I'm just extending the hyper operator from "do this operator several times" to "do this expression several times". "More sensible behavior" is entirely subject to the exact instance at hand. In the case of let's say C< == >, I want to feed it the raw, unexploded junction. I well written C< == > should be able to apply all kinds of optimizations to the task at hand, and provide much more sensible results. I expect calls with operators to be considerably more common than function calls w/ junctions. So if I grant you your default of autothreading, we then get: if $x == »3|4|5« {...} given $x { when »3|4|5« {...} } Which seemed far more suboptimal than the other way around, IMO. These semantics also give us the ability to easily mix and match what we send to a function, so we can say: if funky_test(all(@A), »any(@B)«) {...} sub funky_test ( Junction|Any @a, @b ) { ... } Unless you have a junction, and you wanted it to autothread on the first parameter, rather than be passed in, in order to get some perceived desirable side effect out of funky_test that passing it a Junction would only give a subset of. Suppose funky_test is a derivative of C< printf >. Only this printf let's you feed it a junction for the format, and it will sort through them and see which one matches best depending on actual number of parameters, parameter types, etc. Ordinarily, this would be fairly cool stuff. But let's say you instead wanted it to print the same data with all the different formats. With my calling, you could make the distinction rather easily. With yours, you have to set up the looping yourself. Basically I'm putting all the power of threading into the hands of the caller. The caller is not in a position to know if the callee is internally structured in such a way that passing in a raw junction makes sense. Sure they are. It's called reading the documentation. If it doesn't say it can handle junctions, it probably can't. The right place to say "I can handle a junction, don't autothread" is in the callee; that's the behavior @Larry is proposing. I'm sending the same message. Only my message goes to the programmer, not the runtime. I'm also making it where the decision to insert autothreading code or not is made at compile time, not runtime. As for C< .. >, I'd say that it should handle junctions being fed into it by throwing an exception. Why is this more sensible than returning a list of junctions in list context and a junction of arrayrefs in scalar context? (I believe infix:<..> will return an arrayref in scalar context, though I could be wrong.) (The array of junctions is negotiable, by the way; whatever it is, though, it should probably be the same as the default meaning for list returns from an autothreaded function.) About the only thing is could return would be a lazy list of jun
Re: Junction Values
Brent 'Dax' Royal-Gordon wrote: Rod Adams <[EMAIL PROTECTED]> wrote: The caller is not in a position to know if the callee is internally structured in such a way that passing in a raw junction makes sense. Sure they are. It's called reading the documentation. If it doesn't say it can handle junctions, it probably can't. I don't want to have to stop in the middle of a hundred-line function to think, "Does Store::Market.get act sanely when I give it a junction? Do I need to explode it manually, or will it handle the junction nicely on its own?" You call functions where you don't know what data types they are expecting? That's... surprising. Even in a loosely typed world like Perl, knowing what a sub or method is expecting to be fed seems like a good idea to me. I see checking for accepting junctions as input as being on the same level as "Does it want a list or an arrayref here?". When I'm writing my own insanely large functions, I'm constantly hitting the docs to see the nuances about the method calls I'm not already intimately familiar with. And if I'm going to attempt to use a function in a new way (like feeding it a Junction), I recheck the docs to make sure I'm not setting myself up for trouble down the road. Your mileage may vary. -- Rod Adams. (PS - This should not be construed to be an attack on you or your programming style. It is not. Though I've never seen you in action, I have every reason to believe you are a fully competent developer. It is simply a response to your statement above, explaining why I thought the attitude expressed there represented a weak argument.)
Re: Junction Values
Damian Conway wrote: Rod Adams wrote: All I want now is for autothreading to be explicit. It already *is*. The only way that: is_prime($x) can ever autothread is if $x holds a junction. But that can now only happen if there's an explicit C in scope where $x was assigned to (or the explicit use of some other module that also activates C). So $x having a junction must be a known possibility at that point. Of course, literal junctions *will* autothread in all circumstances: is_prime(any(6,7,8)) is_prime(6|7|8) I had not caught the difference between: use junctions; $x = 6|7|8; if is_prime($x) {...} and if is_prime(6|7|8) {...} before. Is this new, or yet another important detail I missed along the way? Or is this a side effect of not being able to store a Junction, and can go away if C< use Junctions > is turned on? But they're both explicit too: you're explicitly using junction constructors, so the autothreading can hardly come as a surprise. *If* we are guaranteed than an explicitly created junctions will always autothread, I'll agree with this. I will, however, question if this is optimal. Compare two simple cases: C< $x == any(4,5,6) > and C< $x < all(4,5,6) >. Both of them are prime candidates to some optimizations, but the optimizations are likely rather different. If we pass the junction into the operator, then it can perform some custom tailored code, to make things much more efficient, instead of relying on a more generalized junction optimizer to handle things. What this also means is that if you wish to pass an anonymous junction, you can't. You have to do something like: { use junctions; some_func(my $x = any(4|5|6)); } Which just seems silly. And if: is_prime($x) does happen to autothread when you weren't expecting it to, then one of two things will happen. Either the subroutine will be 'pure' in which case there's no problem in autothreading it; or else the subroutine will have side effects, in which case you'll get an explicit warning when the autothreading occurs. I addressed earlier concept of how does perl know when there are side effects, particularly with the execution path can weave to parts written in pure-parrot. In particular, if the Patrick responded by implying that there was no such side effect protection. see: http://www.nntp.perl.org/group/perl.perl6.language/19210 (my post) http://www.nntp.perl.org/group/perl.perl6.language/19212 (Patrick's response) I see your statements on the subject, and Patrick's to be at odds. But then again, it might be that I've misread something again, though I'm doing my best to avoid it now. I request some clarification on this. If nothing else, to make sure you and Patrick have the same understanding of what's happening. This problem goes away completely with explicit autothreading. perl would no longer be making assumptions about what to autothread, and what to carp over. Personally, I think it's completely fascist to require a C pragma in order for junctions to even be stored in variables. It's as bizarre as requiring C or C or C or C would be. Yes, it *is* possible to get unexpected behaviour from passing a junction where it isn't expected, but it's already possible to get unexpected behaviour by passing a string or an undef or a reference or an object where it isn't expected. Junctions are nothing new in that respect. I had it in my head that if I were to get my »Junction« explicit threading idea, I was going to follow up by saying the block against storing junctions was a case of diminishing returns at that point, and should probably go away. I appreciate the stop-gap measure that it was, but I'd prefer to solve the real problem at hand. Ironically, by using the Awesome Power of Junctions: I hope I never gave the impression that I felt Junctions were not powerful... That was not the case. If anything, I was arguing that they were *too* powerful... But in the end, I realized it's just the implicit autothreading I didn't like. Look, I do understand the arguments in the other direction. I've understood them for the past five years that I've been developing the concept of superpositional data-types. I've thought them through numerous times myself, and in the end: I just don't buy them. The whole point of junctions is to make the threading of operations on datasets both automatic and implicit; to make it Do The Right Thing without the hassles of explicit threading. If you don't want that, that's fine: just don't use junctions. Use arrays and hyperoperators instead. And we'll happily give you a C pragma so you can be emphatic about not wanting them. I can certainly understand the "hassles of explicit threading" if one is thinking: $y = func(any(3|4|5)); has to be
Re: Junction Values
Damian Conway wrote: Hmm. On rereading my last message, I feel that it comes across as angry, and critical of this entire discussion or perhaps of particular participants. That was certainly not my intent and I apologize if that's how it appeared. I genuinely respect the contributions of every person on this list, and even when (as now) I strenuously disagree with the ideas expressed, I know that those contributions are sincere and offered with the best interests of Perl at heart. I still stand by every point I made in that last message, but I'm sorry that I let my frustrations leak into the discussion. Damian Well, I for one, never took any offense to any of the responses sent my way. And I appreciate the patience it's likely taken to not just completely Warnock me. However, I also realize that I might have stepped on some toes of the course of this long discussion. Which was never my intention, and I'll apologize to any who feel I've slighted them in the process. I do believe everyone on this list shares the same goals of making Perl 6 the possible language that it can be. However, opinions will vary as to what that actually means. Being a group of people that can by and large be described as having a fairly large egos, these differences of opinion can become rather passionate. And passion leads to some pretty extreme responses. It certainly hasn't helped matters that the exact nature of my proposal has changed in some fairly drastic ways on a regular basis, as I came to a better understanding of what Junctions were, and how they were being implemented. I apologize for any confusion this may have caused, but I do think the resulting discussions have shed some new insights on Junctions, Sets, what it means to have a sigil, why junctions can't just be another class, and several other topics. Poor Mr. Fowles is likely having nightmares figuring out how to summarize all of this. Positions I still stand by: - Sets belong in the language, and need more support. This can likely be done at the module level, but I'd like them better incorporated, preferably with their own sigil. However, I believe they can peacefully coexist with Junctions, and one concept does not need to crowd out the other. - Implicit autothreading is a Bad Thing, and should not happen. This is almost entirely due to the side effects such behavior can generate. To keep the power of junctions viable, explicit threading should be trivially easy, but it should be explicit, none the less. -- Rod Adams
Lingering questions about Junctions.
Okay, Now that I've largely accepted junctions (except implicit autothreading, which is Bad.), I see some corners that need to be poked at in terms of how they fit into the language as a whole. All of these examples assume an appropriate level of "use junctions;" is in effect. - Can junctions be used as array/hash subscripts? In an rvalue context, this makes sense, in that you can simply return a junction of the deferences. But in an lvalue context, this gets dubious for everything except all() junctions. Consider: @x = 1..10; @x[any(4,3)] = 7; What does @x look like now? @x[all(4,3,2)] = 7; makes sense, as long as it means: @x[4,3,2] »=« 7; I don't want to even think about what: @x[none(1,2)] = 7; does. - Can you have non-scalar junctions? As the discussions surrounding C< .. > demonstrated, it's not that hard for someone to create a situation where a junction of lists might come into existence. But let's consider something a step beyond. %x = (a => 1, b => 2, c => 3) | (d => 4, e => 5, f => 6); @y = %x.keys; Does this explode, or does @y have something useful in it now? Before dismissing the concept completely, it's perfectly possible to create something much like a junctive hash via references: %x = (a => 1, b => 2, c => 3); %y = (d => 4, e => 5, f => 6); $z = one(\%x, \%y); @w = $z.keys; - What does it mean to sort a list of junctions? @x = any(1,6), all(2,5), one(3,4); @x = @x.sort; Does sort() carp on junctions, or is it just one of the weird things you have to live with if you're playing with junctions? -- Rod Adams
Re: Junction Values
Damian Conway wrote: Rod Adams wrote: Is this new, or yet another important detail I missed along the way? Or is this a side effect of not being able to store a Junction, and can go away if C< use Junctions > is turned on? Yes, it's a side-effect of the new default prohibition on junction assignments (though I'm still working hard to convince everyone that that prohibition cripples junctions and that having to before you can assign a basic Perl 6 scalar datatype to a variable is an abomination). FWIW, I agree with you that having something half enabled by default make little sense. But I'll accept it as a stop gap until I get my explicit threading. And I really don't like the implications of how turning on "use junctions" can also suddenly change the threading semantics of junctions. Talk about subtleties in action... I imagine some intermediate level programmer decides they are ready to start playing with stored junctions. He adds a "use junctions;" at the top of his file, thus turning it on for all functions written in that package. Suddenly, some of his function calls with stop implicitly threading, and instead start carping in some truly spectacular ways. Said programmer quickly takes away the "use junctions;", and never considers using stored junctions again. It's just not worth the trouble, in his mind. If, however, he was conditioned to put in some »«'s whenever he wanted his junctions to thread, he would not encounter this problem. I will, however, question if this is optimal. Compare two simple cases: > C< $x == any(4,5,6) > and C< $x < all(4,5,6) >. Both of them are prime > candidates to some optimizations, but the optimizations are likely rather different. > If we pass the junction into the operator, then it can perform some custom tailored code, > to make things much more efficient, instead of relying on a more generalized junction optimizer to handle things. Sure. That's why we have the ability to specify subroutines where junctive args are *not* autothreaded, by typing the corresponding parameter as taking a junction: multi sub infix:«==» (YourType $x, Junction $y) is symmetrical {...} multi sub infix:«<» (YourType $x, Junction $y) is symmetrical {...} These two multisubs can optimize for junctive arguments to their hearts' content. I guess I misunderstood your statement of "literal junctions *will* autothread in all circumstances" to mean _all_ circumstances, not just ones where the callee didn't explicitly say they could accept them, or if the current "use junctions;" status is in alignment with the moon, or other such things. I will allow you to alter that statement if you now find it insufficiently qualified. I don't see that Patrick's response implies that at all. In fact, I think his statement that: >> Well, the ultimate answer is that both Dan and Patrick (and others) >> will negotiate the exact interface when we get to that point, and >> that we don't seem to be too concerned about it at the moment. >> (It could just be that we're both burying our heads in the sand >> hoping it'll be magically "solved" by the other. :-) >> >> However, in working out these examples I'm fairly comfortable that >> it can be made to work at the Perl 6 compiler level if need be, >> although it will probably be a lot more efficient if we can find a >> way to do it within Parrot. seems to confirm that detecting and reporting autothreaded side-effects is entirely possible. Let me attempt to clarify the discrepancy as I see it. I'll take Damian's recent comment of: " And if C< is_prime($x) > does happen to autothread when you weren't expecting it to, then one of two things will happen. Either the subroutine will be 'pure' in which case there's no problem in autothreading it; or else the subroutine will have side effects, in which case you'll get an explicit warning when the autothreading occurs. " and my 19210 code of: $x = 3|4; $y = fun($x); sub fun ($x) { warn "enter: fun($x)\n" if $DEBUG; $x + 1; } I hope it's clear that whether or not fun() has side effects is a runtime decision, and can't realistically be determined at function call time. Now, let's assume that this falls under Damian's heading of "happens to autothread when I wasn't expecting it to." If $DEBUG is off, no worries. If $DEBUG is on, I expect my explicit warning, as promised. What I am questioning is how perl decides when to give my warning. Does perl inspect fun() to see if there are any side effect causing calls in it? Or does it keep an internal note to itself saying "I'm autothread
Re: Junction Values
Damian Conway wrote: Rod Adams wrote: I never want to see implicit threading. Ever. If this is the only stumbling block, then it's easily solved. Instead of ruining junctions by imposing all kinds of complex and annoying hoops and hurdles (i.e. C and C), we can just offer a C pragma that prevents any non-explicit junction from autothreading any operator or subroutine. Put it at the top of your code and you'll never get any implicit threading. Well, allow me to explain what I want in a little more detail, so I can be sure I'm getting it. I want to be able to feed a junction to functions that handle it, but I also want to thread over ones that do not. But I do not want the decision of which way to go to be made for me. So, I want to be able to pass a raw junction into C< == >, because it understands junctions, and will take care of the threading for me, likely in a way that's much more efficient than my generalized »« threading ever could. I do not consider this implicit threading. It's passing the task of threading off to C< == >, which itself performs some form of explicit threading. But when I'm faced with some function that does not directly support junctions, or one which does, but not in a way that I like, I want to be able to thread my junction over it. I do not think that what you said above is enough to accomplish this. I believe what I need to separate your threading desires from mine is two fold: 1) I need my »« modifier which forces explicit threading, which will not normally be needed under "use autothreading;" conditions. 2) I need "no autothreading;" to alter the calling syntax to require »« when threading is desired (or you can do a .values() and .junctiontype() and roll your own if you really want to). But I can still pass junctions around at will, withstanding normal type check requirements. Then the only argument left is whether "use autothreading" or "no autothreading" should be default. I would, of course, say "no autothreading;", and then turn back on the ability to store junctions. IMO, "no autothreading" would provide enough cover for the unsuspecting, removing the Bad Side Effects problems that spawned Larry's no junction storage default. At the same time, junctions still have enormous power via the »«. If people don't want to have to bother figuring out when to thread for themselves, they can then turn on "use autothreading", and let perl attempt to figure it out for them. Also, if "no autothreading" is default, the person new to Perl6 will always have something to present to investigate to figure out what is going on. In my code, it'll be the funny looking C< »$junction« > things. In your code, it'll be the C< use autothreading; > at the top of the page. The only implementation problem I see is a potential for the »« to be mis-parsed, since » and « seem to be serving several different roles these days, but I don't think any of them conflict with this meaning. If you want to rename »« to something else, I'm open to suggestions. Just leave it fairly simple. As for why implementation should be easy (or at least the delta between your way and my way is easy): - The functionality of »$junction« has to be defined anyways if autothreading happens. It's just calling an already existent chunk of code. - The logic of when to thread becomes: given $situation { when marked_with_»«() { thread } when use_autothreading() & damians_ouija_board() { thread } default { don't thread } } And you've already defined how the ouija board works, everything else should be boilerplate for the compiler/runtime to handle. This sound reasonable enough? -- Rod Adams
Re: Junction Values
Nigel Sandever wrote: On Sat, 19 Feb 2005 18:42:36 +1100, [EMAIL PROTECTED] (Damian Conway) wrote: The Awesome Power of Junctions: As I tried to express elsehwere, this what I'm looking for. Instinctively, and for a long time since I first came across Q::S, I thought that the "killer app" of Junctions is there somewhere, I'm just not seeing it yet. I'd really like to see some practical demonstrations of the Awesome Power. Something that goes beyond producing a boolean result from a set of values that could equally be done using hyperoperators? Well, that was one of my stumbling blocks early on. They don't really give you the power to do anything you couldn't previously do. They just make certain things a lot easier to do. But I'll take a whack at giving you something non-trivial to do without junctions: $re1 = /^ <-[x]>* x <-[x]>* $/; # match a string with exactly one 'x' in it. $re2 = /^ <-[y]>* y <-[y]>* $/; # ditto 'y' $re3 = /^ <-[z]>* z <-[z]>* $/; # ditto 'z' $re4 = all($re1, $re2, $re3); # matches if x,y, & z all appear exactly once, in any order. $re5 = one($re1, $re2, $re3); # matches if there is exactly one x, y, or z $re6 = any($re1, $re2, $re3); # matches if there is at least one of x,y,z that appears exactly once. $re7 = none($re1, $re2, $re3); # matches if there are 0 or 2+ of each of x,y,z. And all seven of these can be used as any stored RE can: if $x ~~ $re6 {...}; given $x { when $re5 {...} when 'santa' {...} when ($re1 | $re3) & $re3 {...} } Looking at the junctioned RE's: #6 would is straight forward to do as a single RE in this case, and in the general case. #5 would be fairly trivial to in this case, but not in the general case. #4 is possible with a lot of zero-length look aheads and look-behinds, but very ugly. #7 I have no idea how to attack as a single RE in anything close to approaching elegance. So what have we gained here? The ability to join several RE's together, into something that still acts like a single RE. Show me the equivalent code without junctions, and then we'll compare the power of junctions. btw, the examples above assume the ability to store a junction. So you either have to 'use junctions;', or convince Larry to rescind that restriction. HTH. -- Rod Adams
Re: Junction Values
Damian Conway wrote: Rod Adams asked: > This sound reasonable enough? Frankly, no. ;-) Sorry, but your latest proposal sounds complex, multiply special-cased, and way too much of an imposition on the programmer (which is specifically what junctions are supposed to avoid). Funny. I thought it was simple and elegant. My explanation might have been complex, as well as the motivations, but I truly considered it a straight forward and simple solution. As for "too much of an imposition on the programmer", that's essentially what I was asking for all along. To be imposed upon to decide when threading occurs. I won't apologize for that, or change my position on it. But I was making the imposition optional. And, actually, now that I better understand your latest proposal, I realize how amazing close we are. Then, if you don't want implicit autothreading, you can turn it off completely: C. And if you want explicit (non-auto)threading, you can use an explicit junction, even under C: is_prime( any($x) ) Change that C< any($x) > to C< »$x« >, and the important differences between our positions shrink dramatically. Reason I don't like any() here is that $x already has a junctive condition on it. While any() with a single value does not change in the least how this will be evaluated in the long run, it could be confusing to wrap an all() junction inside an any() call. Doubling up the type works for all the types except none(). Use »« for an explicit call designator, and you revert to the type already in the junction. Give me my »« as a secondary way of always explicitly threading, and I'll go away happy. You can keep the rest of your proposal the same. I'll just start using them wherever I think threading should happen, even if I never needed to use them in most of the places I will. It'll be a good visual to myself of what's going on. Don't give them to me, and I'll frown for a while, but then likely get over it. I truly appreciate the thought and effort that all of you--especially Rod and Patrick--have put into this discussion, but I'm afraid I have to bow out of it now. I understand bowing out of this perfectly. There other tasks whose time I've raided for this discussion, and the backlog is starting to look pretty nasty. But it has been a good and healthy discussion. Many things have come of it. Thanks to all the participants. PS: FWIW, I'd have absolutely no objection to us adding a fifth core junctive type (perhaps C, perhaps just C ;-) that has *no* associated predicate, but which implements full set semantics: my $x = set(1..3); my $y = set(1,3,5,7,9); my $n = 2; $x | $y # set(1,2,3,5,7,9) $x & $y # set(1,3) $x - $y # set(2) !$x # set(none(2));-) $x < $y # $x is a proper subset of $y $x <= $y # $x is a subset of $y $x == $y # $x is the set $y $x ~~ $y # $x is the set $y $n < $y # $n is an element of $y $n ~~ $y # $n is an element of $y set()# empty set $x.values# list of elements of set $x $x.powerset # power set of $x $x x $y # cross product of $x and $y # etc., etc. Now THAT is an even better idea than the separate Set class I was going to champion whenever I next had time for such a thing! I support this concept fully! -- Rod Adams PS - Looks like Matt gets his wish. This juggernaut of a thread is coming to a close. I'd be happy to proof his summary of it if he gives me an advanced copy.
Re: Junction Values
Eirik Berg Hanssen wrote: Rod Adams <[EMAIL PROTECTED]> writes: $re1 = /^ <-[x]>* x <-[x]>* $/; # match a string with exactly one 'x' in it. $re2 = /^ <-[y]>* y <-[y]>* $/; # ditto 'y' $re3 = /^ <-[z]>* z <-[z]>* $/; # ditto 'z' $re7 = none($re1, $re2, $re3); # matches if there are 0 or 2+ of each of x,y,z. #7 I have no idea how to attack as a single RE in anything close to approaching elegance. Depending on your idea of elegance ... anchored zero-width negative lookahead: $re7 = qr/^ (?!= $re1 | $re2 | $re3 ) /x; Oh right. Perl6. Well, if I understand "<$re1>" correctly, I think this is what it will look like: $re7 = /^ | <$re2> | <$re3> > /; That doesn't quite do it, but something along those lines is possible. You'd have to make sure the look ahead/behinds match to the end of the string, not just some substring. And then you'd have to put in something to actually match the string. So possible, but not straightforward in the least. I still want junctions, but I also still am not quite sure how they will behave. For instance, I wonder how this would autothread or not: my sub f (Int $x) { if $x { return 0, 1, $x; } else { return 0, 1; } } my $j = 0 | 7; my @a = (1, f($j), 0); - How many elements are there in @a? 3? 5? 4|5? - What is @a[-1]? 0? any(0)? 0|undef? - What is @a[4]? undef? 0|undef? 0? Naïvely, I would expect that setting of @a be equivalent to this: my @a = (1, ([0,1]|[0,1,7]), 0); And so from the callers perspective, &f, which usually returns two or three values, suddenly returns a single (junctive) value. New semantics for &f, courtesy of autothreading. I expect this is too naïve. But what am I missing? I believe you are correct in your analysis. It's also something that I will cover as soon as I have time to write down the revelation I had about junctions laying in bed last night. (Don't cringe everyone. I actually figured out why Damian insists on implicit threading. And I agree with him. Now I want to clamp a completely different kind of restriction on Junctions.) I might be able to find time for it late tonight. Might take a few days. -- Rod Adams
Junctions, Sets, and Threading.
ing operation that they lost with the Prime Junction Rule. Since all the »'s and «'s floating around make this explicit threading, there are no nasty surprises laying around. You never have a scalar suddenly explode into a list, causing no end of havoc in unsuspecting code. These are also infinitely more useful, since you can be guaranteed that they won't short circuit, and they are in exactly the order you specified. So that's how I feel about things. The Prime Junction Rule was the big revelation I had the other night. The rest of this was the logical consequence spawned off that single thought to make it a complete idea. I think that overall in this process I've done the following: - Kept the real power of Junctions intact. - Provided fairly strong protection for newbies, without sacrificing power. - Kept Nasty surprises to a minimum. - Got rid of the need for "half on" features. - Provided back any power that the Prime Rule removed through sets and expanded hyper ops. -- Rod Adams
Re: Junctions, Sets, and Threading.
Damian Conway wrote: Rod Adams wrote: > The purpose of a junction is to allow for performing several tests at a > given time, with the testing code needing no knowledge of that junctions > are present. While a junction can represent several values at the same > time, such notions as "hold" and "contain" should be avoided, and they > can be very misleading, they betray the fact that a junction is a single > entity. As such, junctions are best thought of as Scalar. (Like other > scalars, it may reference to something much more complex, but that's > beside the point). Therefore the result of a junction evaluation should > be Scalar. Everything is okay to here. [snip] > Therefore, the only place that it makes sense to evaluate a junction > is in a place where a boolean value is expected. This brings us to our > "Prime Junction Rule": > > Junctions can only be evaluated as part of a boolean expression. No. > Attempting to evaluate a junction anywhere else is an error. No. This is my major point of the post. In my opinion, your example of: # Print a list of substrings... my $substring = substr("junctions", any(1..3), any(3..6)); say $substring.values(); Is a perfect example of a place where saying: # Print a list of substrings... my @substring = substr("junctions", »1..3«, »3..6«); say @substring; Is far more in line with what you're doing. Not to mention you likely wanted it to do: my @substring = substr("junctions", »1..3«, »3..6«); say [EMAIL PROTECTED]; instead, putting nice "\n"s between values. My way also guarentees a certain order to the output. Simply put, you're ignoring the fact that junctions have a boolean predicate. Which they do. In this example, it didn't matter if you had used any/all/one/none. > - There is still a limited case of "Nasty Side Effect Syndrome" that can > be caused by having an assignment, output, or other undesirable type of > function/operator as part of a boolean expression. There will therefore > need to be a "is unautothreadable" trait to be had for functions. All > builtin I/O and assignment functions should have this on. This > protection is shallow. If the call is not in the text of the evaluated > expression, it is not guaranteed to be tested. I need to think about this. I'm not sure I'm convinced this isn't covered by none(Junction) typing on parameters. It is not. By my proposal: $j = any(1,2,3); unless say($j) { die '...' } The say would thread, because of the boolean expression in the 'unless'. C< say > does not get the junction as a parameter. But C< say > needs to be marked that it's a no-no to thread over it. > - If you wanted to thread a junction in a non-boolean way, you probably > didn't want a junction. You likely either wanted an array or a set, and > some combination of hyper operators. See below. Not convinced of this. I am completely convinced of this. Please express your reservations so I can address them. > Sets > > > Despite several surface similarities between a set and a junction, they > are quite different. Sets actually contain other things. Junctions hold > several values at once, and can even hold the same value more than once > at once. Err, no. Junctions *are* values, and those values are unique. $x = one(2,3,3); squishing the duplicate 3 is not allowed here. > Sets are inherently plural in thought process. Junctions are > inherently singular. The operations one wishes to perform on a set are > radically different from those performed on a junction. True. > Sets and hashes are an odd pair. Hashes are not a good basis for Sets > due to the restriction that the keys are strings. Even if this is not > the case, It's not. Changing the index type of hashes away from Str makes as much sense to me as changing the index type of arrays to something non-integral. None. > In addition, a set evaluated in a list context returns it's members. Err...then how do you create a list of sets??? grumble. Didn't think of that. I was looking for a simple way to say: for $set {...} without throwing all kinds of special cases around. > In addition to C< ~~ > for membership, we will borrow the {} > subscripters from hashes (not sure about the <> or «» variants). You'd have to take them, I'm afraid. Introducing gratuitous inconsistencies would be a Bad Idea. That's acceptable. > In this form, a C< $set{$key} > reference will look for the element > that matches the place in the sort identified by $key (in other > words, the element with the matching .key() or value). If something > is there, it then returns C< .value||$_ >, assuming $_ is the element > at that
Re: Junctions, Sets, and Threading.
Damian Conway wrote: Rod Adams wrote: This is my major point of the post. In my opinion, your example of: # Print a list of substrings... my $substring = substr("junctions", any(1..3), any(3..6)); say $substring.values(); Is a perfect example of a place where saying: # Print a list of substrings... my @substring = substr("junctions", »1..3«, »3..6«); say @substring; Is far more in line with what you're doing. But much less obvious. This is the core of my qualms. You're proposing we have all three of: »foo« @x, @y; foo [EMAIL PROTECTED], [EMAIL PROTECTED]; foo [EMAIL PROTECTED]@y»; all meaning very different things. That really worries me. I'd especially prefer that we didn't overload »« to mean both "linear vector" and "cross-product". I certainly like the idea of having both abilities available; I'm just think the syntaxes need to be better differentiated. I'm not pinning everything on the syntax being » «. I just hadn't heard the objection to it before so was running with it. If it takes changing them to something else, I'll go with that. Though I was hoping for something shorter than C. I also like the use of operators here, since they are making a substantial change to the entire statement. All of any/all/one/none/every look too much like ordinary function calls for my tastes. But we do seem to be mighty short on unambiguous punctuation these days. However, I would have picked the « » as qw// to be the loser in this regard. Then the »'s and «'s all mean "repetition is happening". I personally never found C< $x{qw/dog cat foo/} > to be a bother, and I use the equivalent in Perl5 very frequently. _If_ that is dropped, then you can have « » mean "linear vector" and » « mean "cross product". But I won't press this idea. As for "obvious", I was processing two lists of parameters, and got back a 2-D array, where I could easily match up each input to result. You returned something of the form any(any(),any(),any()), where there is no way to match which result was from a given input. (FWIW, we both get garbage for output and/or errors. You're printing raw junctions, I'm printing arrayrefs.) I would wager that most people attempting this sort of thing would find a 2-D array to be a much more obvious result than a nested junction. Simply put, you're ignoring the fact that junctions have a boolean predicate. Which they do. Yep. Isn't it useful that you can do that, and get more functionality out of a single construct? Powerful? Yes. Scary? Very. I start with something that looks like a scalar, and all the code it touches turns all my other variables into juxtapositions. Kind of like taint checking. Useful? No more so that hyperquotes in the same place. I find it more useful to get even more functionality out of the list construct. I need to think about this. I'm not sure I'm convinced this isn't covered by none(Junction) typing on parameters. It is not. By my proposal: $j = any(1,2,3); unless say($j) { die '...' } The say would thread, because of the boolean expression in the 'unless'. C< say > does not get the junction as a parameter. But C< say > needs to be marked that it's a no-no to thread over it. But that was precisely my point: sub say (none(Junction) [EMAIL PROTECTED]) {...} In my way, C< say > is never given the chance to accept or decline $j as an argument. The above would be handled as: unless any(say(1), say(2), say(3)) {...} All C< say > sees is scalars, one at a time. I was looking for a way to mark C< say > with a way to tell the callee that threading over it (note: "over" not "through") is a bad idea. I am completely convinced of this. Please express your reservations so I can address them. sub get_matches { my @in = split //, prompt 'search for: '; my @out = split //, prompt 'but not: '; return %data{any(@in) & none(@out)}; } my $data = get_matches(); No booleans anywhere in sight. So with example data: @in = qw/foo bar baz/; @out = qw/baz fiz bop/; %data = (foo => 5, bar => 6, baz => 7, fiz => 5, bop => 8); you return: all(any(5,6,7), none(7,5,8)) Which is just 6. If I were a user of this function, I would want foo's 5 as well. And I'd probably prefer to have had them as a list, not a junction. By delaying the application of your predicates, you have voided whatever it was that made those values have those predicates associated with them. Logic would say that each step of processing of the values in the junction without the application of the predicate would more often than not move you further and further away from the correct
Re: scoping functions as list operators?
Luke Palmer wrote: We have discussed making equals low precedence enough to eliminate the parentheses in the standard swap: $x, $y = $y, $x; $x, $y <== $y, $x; -- Rod Adams
Re: scoping functions as list operators?
Luke Palmer wrote: Now we just need to determine if 'my' can leave its post as a unary declarator. Don't see why not... If you ever need it unary, you can just put the () back in. The question becomes which is more common: Scoping a single variable in a list context, or scoping several variables at once. Likely the later. This also reminds me of the thought someone had a while back about making = not copy in list context, making people use ==>/<== for all list assignments. It would certainly take care of the : $x, $y = $y, $x; problem that will have people scratching their heads. (assuming that doesn't trigger a warning/error). Overall, I like the protection it provides, but dislike the extra three keystrokes it means for something I use so often. -- Rod Adams
Re: scoping functions as list operators?
Uri Guttman wrote: that fixes Stéphane's problem with my yall proposal. and yall solves the unary my problem. :) Stop misusing "y'all" before this Texan has to hurt you. And y'all wonder why we hate you damn yankees. Can't even speak properly up there. :-) We should instead have a list attribute, so we can say: $x, $y, $z are mine! mine! mine!; (Must be spoken like a three year old when read.) -- Rod Adams
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