Re: Support for ensuring invariants from one loop iteration to the next?
On 2008-Dec-17, at 5:15 pm, Aristotle Pagaltzis wrote: The way Template Toolkit solves this is far better: the loop body gets access to an iterator object which can be queried for the count of iterations so far and whether this is the first or last iteration. Well, I prefer a built-in counter like that, but I thought the point was that you wanted some kind of block or something that could be syntactically distinct? -David
Re: Support for ensuring invariants from one loop iteration to the next?
* David Green david.gr...@telus.net [2008-12-18 19:45]: Well, I prefer a built-in counter like that, but I thought the point was that you wanted some kind of block or something that could be syntactically distinct? No, that would only be a means to the end. That end is simply to not repeat myself in writing honest code. And I just realised how to best do that in Perl 5: goto INVARIANT; while ( @stuff ) { $_-do_something( ++$i ) for @stuff; INVARIANT: @stuff = grep { $_-valid } @stuff; } I am not sure why this works, to be honest. That is, I don’t know whether it’s an intentional or accidental feature that execution doesn’t merely fall off the end of the loop body after jumping into the middle of it, but loops back to the top, despite not having executed the `while` statement first. But it does work. And it says exactly what it’s supposed to say in the absolutely most straightforward manner possible. The order of execution is crystal clear, the intent behind the loop completely explicit. -- *AUTOLOAD=*_;sub _{s/(.*)::(.*)/print$2,(,$\/, )[defined wantarray]/e;$1} Just-another-Perl-hack; #Aristotle Pagaltzis // http://plasmasturm.org/
Re: Support for ensuring invariants from one loop iteration to the next?
On Fri, Dec 19, 2008 at 01:47:08AM +0100, Aristotle Pagaltzis wrote: : And I just realised how to best do that in Perl 5: : : goto INVARIANT; : : while ( @stuff ) { : $_-do_something( ++$i ) for @stuff; : : INVARIANT: : @stuff = grep { $_-valid } @stuff; : } : : I am not sure why this works, to be honest. That is, I don’t know : whether it’s an intentional or accidental feature that execution : doesn’t merely fall off the end of the loop body after jumping : into the middle of it, but loops back to the top, despite not : having executed the `while` statement first. : : But it does work. : : And it says exactly what it’s supposed to say in the absolutely : most straightforward manner possible. The order of execution is : crystal clear, the intent behind the loop completely explicit. It is specced to work correctly in Perl 6 as well. The policy (shared with Perl 5) is that you may use goto into any loop that doesn't depend on an initializer. It's illegal to go into a for 1..10 loop, for instance, since the loop won't be initialized correctly. Larry
Re: Support for ensuring invariants from one loop iteration to the next?
Aristotle Pagaltzis wrote: And it says exactly what it's supposed to say in the absolutely most straightforward manner possible. The order of execution is crystal clear, the intent behind the loop completely explicit. If it works for you, great! Personally, it doesn't strike me as being as straightforward as putting a last unless clause into the middle of an otherwise-infinite loop; but then, that's why Perl (both 5 and 6) works on the principle of TIMTOWTDI: you do it your way, and I'll do it mine. -- Jonathan Dataweaver Lang
Re: Support for ensuring invariants from one loop iteration to the next?
* David Green david.gr...@telus.net [2008-12-16 18:30]: So what if we had LOOP $n {} that executed on the nth iteration? Ugh. Please no. Now you suddenly have this odd new corner of the language with all its very own semantics and you have to figure out how to make it orthogonal enough and when it’s evaluated and a million other details in order to make it actually useful, and in the end you have a bigger language with yet another mechanism bolted on. The way Template Toolkit solves this is far better: the loop body gets access to an iterator object which can be queried for the count of iterations so far and whether this is the first or last iteration. Thay would result in the following: repeat { @stuff = grep { !.valid }, @stuff }; ENTER { next if $.first; .do_something( ++$i ) for @stuff; } } while @stuff; And now suddenly you don’t need to spec out a complicated single- purpose mechanism, and you can still realise far more powerful control flows than the single-purpose mechanism could ever hope to provide. Not only that, but you get access to the information as data in the program so you can do many more things with it compared to if it were locked up in the invocation semantics of a closure trait. `FIRST` and `LAST` are justifiable regardless of what other mechanisms are available simply because they’re things you want so frequently. `LOOP n` is just overgeneralisation. Thumbs down. Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/
Re: Support for ensuring invariants from one loop iteration to the next?
On 2008-Dec-6, at 7:37 am, Aristotle Pagaltzis wrote: Funnily enough, I think you’re onto something here that you didn’t even notice: [...] if we had a NOTFIRST (which would run before ENTER just as FIRST does, but on *every* iteration *except* the first), then we could trivially attain the correct semantics and achieve all desired results: repeat { @stuff = grep { !.valid }, @stuff }; NOTFIRST { .do_something( ++$i ) for @stuff; } } while @stuff; The really nice thing about this is that the blocks are nested, so that any variable in scope for the invariant enforcement will also be in scope in the NOTFIRST block without the user ever having to arrange another enclosing scope. Oh, yes! So what if we had LOOP $n {} that executed on the nth iteration? LOOP 0 {} at the beginning would be like FIRST {}, LOOP * {} at the end would be like LAST {}, and LOOP 1..* {} would give us the NOTFIRST block. Presumably you could have multiple LOOP blocks too. (Actually, you couldn't quite do FIRST/LAST using LOOP $n, because FIRST/LAST occur outside ENTER/LEAVE, whereas LOOP would occur inside. But perhaps you could have LOOP blocks inside ENTER/LEAVE blocks?) -David
Re: Support for ensuring invariants from one loop iteration to the next?
On Tue, 16 Dec 2008, David Green wrote: On 2008-Dec-6, at 7:37 am, Aristotle Pagaltzis wrote: Funnily enough, I think you?re onto something here that you didn?t even notice: [...] if we had a NOTFIRST (which would run before ENTER just as FIRST does, but on *every* iteration *except* the first), then we could trivially attain the correct semantics and achieve all desired results: repeat { @stuff = grep { !.valid }, @stuff }; NOTFIRST { .do_something( ++$i ) for @stuff; } } while @stuff; The really nice thing about this is that the blocks are nested, so that any variable in scope for the invariant enforcement will also be in scope in the NOTFIRST block without the user ever having to arrange another enclosing scope. Oh, yes! So what if we had LOOP $n {} that executed on the nth iteration? LOOP 0 {} at the beginning would be like FIRST {}, LOOP * {} at the end would be like LAST {}, and LOOP 1..* {} would give us the NOTFIRST block. Presumably you could have multiple LOOP blocks too. (Actually, you couldn't quite do FIRST/LAST using LOOP $n, because FIRST/LAST occur outside ENTER/LEAVE, whereas LOOP would occur inside. But perhaps you could have LOOP blocks inside ENTER/LEAVE blocks?) Or, instead of having a new block, just add the iterator indicator to the NEXT block, and get rid of ENTER and LEAVE. That way, you'd have this sequence: - FIRST {} - NEXT 0 {} # Replaces ENTER - NEXT 1..* {} # Does NOTFIRST - NEXT * {} # Replaces LEAVE - LAST {} Would that do it? The difficulty to my mind would be sequencing the NEXT blocks; does the NEXT 1..* run before or after NEXT 2..(*-2) ? Maybe we need a NEXT stack. :) - | Name: Tim Nelson | Because the Creator is,| | E-mail: wayl...@wayland.id.au| I am | - BEGIN GEEK CODE BLOCK Version 3.12 GCS d+++ s+: a- C++$ U+++$ P+++$ L+++ E- W+ N+ w--- V- PE(+) Y+++ PGP-+++ R(+) !tv b++ DI D G+ e++ h! y- -END GEEK CODE BLOCK-
Re: Support for ensuring invariants from one loop iteration to the next?
How do you compute '*'? That is, how do you know how many more iterations you have to go before you're done? Should you really be handling this sort of thing through an iteration count mechanism? How do you keep track of which iteration you're on? Is it another detail that needs to be handled behind the scenes, or is the index of the current iteration available to the programmer? (Remember, we're dealing with 'while' and 'loop' as well as 'for'.) -- Jonathan Dataweaver Lang
Re: Support for ensuring invariants from one loop iteration to the next?
On Tue, 16 Dec 2008, Jon Lang wrote: How do you compute '*'? That is, how do you know how many more iterations you have to go before you're done? In some cases, it won't have to be computed, in some cases it won't be computeable (which should be an error). I'd say it'd be fair enough to say that 1..(*-1) should be an error in non-bounded(?) loops (ie. while). Just figure things out when we can, and when we can't, give an error. Should you really be handling this sort of thing through an iteration count mechanism? How do you keep track of which iteration you're on? Is it another detail that needs to be handled behind the scenes, or is the index of the current iteration available to the programmer? (Remember, we're dealing with 'while' and 'loop' as well as 'for'.) I'd say track it if necessary, kinda like the regex variables in Perl5 that imposed a performance hit. Have a magic variable that tracks the loop count if: - The variable is referred to anywhere - Any of the NEXTs require it It seems like the NEXT queue I suggested is already specced (although without the iterator count thingies). I'm also starting to wonder what we do with the return values of the NEXT blocks :). :) - | Name: Tim Nelson | Because the Creator is,| | E-mail: wayl...@wayland.id.au| I am | - BEGIN GEEK CODE BLOCK Version 3.12 GCS d+++ s+: a- C++$ U+++$ P+++$ L+++ E- W+ N+ w--- V- PE(+) Y+++ PGP-+++ R(+) !tv b++ DI D G+ e++ h! y- -END GEEK CODE BLOCK-
Re: Support for ensuring invariants from one loop iteration to the next?
On 2008-Dec-16, at 6:21 pm, Timothy S. Nelson wrote: Or, instead of having a new block, just add the iterator indicator to the NEXT block, and get rid of ENTER and LEAVE. That way, you'd have this sequence: - FIRST {} - NEXT 0 {} # Replaces ENTER - NEXT 1..* {} # Does NOTFIRST - NEXT * {} # Replaces LEAVE - LAST {} Would that do it? Not quite -- the idea is that you could put the LOOP block anywhere in the body of the loop, and it would execute at that point. NEXT and friends always occur at the end (or beginning) of their block. Nor would it work to take an existing block like NEXT and allow it to be positioned in the middle of the body, because it wouldn't be possible to duplicate what they already do -- in this example, the NEXT wouldn't get executed when next if something() occurs: loop { next if something(); a; NEXT { ... } b; } On Tue, 16 Dec 2008, Jon Lang wrote: How do you compute '*'? That is, how do you know how many more iterations you have to go before you're done? In some cases, it won't have to be computed, in some cases it won't be computeable (which should be an error). I'd say it'd be fair enough to say that 1..(*-1) should be an error in non-bounded(?) loops (ie. while). That sounds right to me. Does 'for @foo' take a snapshot of @foo, or can you change the bounds by changing @foo while the loop is running? In which case trying to count back from * might be an error for anything except constant bounds. -David
Re: Support for ensuring invariants from one loop iteration to the next?
On Thu, Dec 04, 2008 at 04:40:32PM +0100, Aristotle Pagaltzis wrote: * [EMAIL PROTECTED] [EMAIL PROTECTED] [2008-12-03 21:45]: loop { doSomething(); next if someCondition(); doSomethingElse(); } I specifically said that I was aware of this solution and that I am dissatisfied with it. Did you read my mail? While this is still the same solution that you dislike, how about recasting it a bit: loop { PRE_CONDITION: { doSomething(); } last unless someCondition(); BODY: { doSomethingElse(); } } That uses additional indenting and labelling to identify the iteration-setup and actual loop body parts, and keeping the termination condition easily visible with non-indenting.
Re: Support for ensuring invariants from one loop iteration to the next?
* David Green [EMAIL PROTECTED] [2008-12-05 15:45]: I tried to break down the reasons for wanting to write such loops different ways: 1) Simple code […] 2) Clear code […] 3) Self-documenting code […] Yes, exactly right. What we need is something a bit like the continue block, except that it gets executed before the loop- condition is checked the first time. So what if we split the loop-body into two parts? repeat { something(); } while ( condition(); ) { something_else(); } Now the condition is in the middle and is syntactically separate. (It's still not up front, but if the first block is really long, you can always... add a comment!) I actually don’t think putting the condition up front is the most desirable constellation. I just want the condition syntactically highlighted and separated from both the loop body and the invariant enforcement. In fact, it seems more desirable to have the invariant enforcement up top because the order of the code then corresponds to the order of evaluation. That is the reason I wasn’t quite happy with its being rendered as a closure trait. Funnily enough, I think you’re onto something here that you didn’t even notice: the following has the right semantics, apart from the fact that it doesn’t perform any work: repeat { @stuff = grep { !.valid }, @stuff }; } while @stuff; Now if we had a NOTFIRST (which would run before ENTER just as FIRST does, but on *every* iteration *except* the first), then we could trivially attain the correct semantics and achieve all desired results: repeat { @stuff = grep { !.valid }, @stuff }; NOTFIRST { .do_something( ++$i ) for @stuff; } } while @stuff; The really nice thing about this is that the blocks are nested, so that any variable in scope for the invariant enforcement will also be in scope in the NOTFIRST block without the user ever having to arrange another enclosing scope. * David Green [EMAIL PROTECTED] [2008-12-05 16:50]: Well, you don't need a comment -- why not allow the condition to come first? repeat while ( condition(); ) { something(); }, { something_else(); } You need the comma there because the final semicolon is optional, and we don't want Perl to think it's an ordinary loop followed by an independent block. Probably better is to name the introductory block, and then programmers as well as compilers know that something unusual is going on: repeat while (condition) preamble { something } { something_else } What I don’t like about these solutions is: how do you indent them? If you try multiple statements on multiple lines within the blocks, then suddenly there is no good and natural indentation style for at least one of the blocks. Also, you are supposed to be able to leave the parentheses off the `while` condition in Perl 6, and then it breaks down visually, particularly if you throw an arrow in there. Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/
Re: Support for ensuring invariants from one loop iteration to the next?
On 2008-Dec-4, at 9:09 am, Aristotle Pagaltzis wrote: And while it does seems like a closure trait, that seems somewhat problematic in that the order of evaluation is weird when compared to other closure traits, which I suppose is what led you to declare the “coy” solution as the most natural. I tried to break down the reasons for wanting to write such loops different ways: 1) Simple code -- the coy solution, with the condition checked in the middle of the loop, is the cleanest in that if we put the condition anywhere else, we still also need to mark where in the middle it should be checked. 2) Clear code -- putting the condition up front (or maybe at the end) makes it stand out and more clearly identifies the purpose of the loop. Of course, you still need something in the middle as well as up front, so you could simply put a comment up front to explain what's going on. 3) Self-documenting code -- this is different from the previous point (introspection rather than [non-self] documentation... like my other comment about counting iterations -- you can always add $i++; #to check for second loop, but then the meaning is accidental rather than implicit). I think this gets at the heart of the problem: not merely making code do the right thing, but making it look the right way, making it use a natural idiom. So something like: repeat using $block { something(); check-condition; # means: last unless $block; something_else(); } But I don't really like the need to add the check-condition command. Maybe something like: repeat using LABEL { something(); LABEL: last unless $block; something_else(); } But that still seems too sloppy. What we need is something a bit like the continue block, except that it gets executed before the loop- condition is checked the first time. So what if we split the loop- body into two parts? repeat { something(); } while ( condition(); ) { something_else(); } Now the condition is in the middle and is syntactically separate. (It's still not up front, but if the first block is really long, you can always... add a comment!) -David
Re: Support for ensuring invariants from one loop iteration to the next?
On 2008-Dec-5, at 7:43 am, David Green wrote: Now the condition is in the middle and is syntactically separate. (It's still not up front, but if the first block is really long, you can always... add a comment!) Well, you don't need a comment -- why not allow the condition to come first? repeat while ( condition(); ) { something(); }, { something_else(); } You need the comma there because the final semicolon is optional, and we don't want Perl to think it's an ordinary loop followed by an independent block. Probably better is to name the introductory block, and then programmers as well as compilers know that something unusual is going on: repeat while (condition) preamble { something } { something_else } -David
Re: Support for ensuring invariants from one loop iteration to the next?
* [EMAIL PROTECTED] [EMAIL PROTECTED] [2008-12-03 21:45]: loop { doSomething(); next if someCondition(); doSomethingElse(); } I specifically said that I was aware of this solution and that I am dissatisfied with it. Did you read my mail? * Jon Lang [EMAIL PROTECTED] [2008-12-03 20:10]: Aristotle Pagaltzis wrote: * Bruce Gray [EMAIL PROTECTED] [2008-12-03 18:20]: In Perl 5 or Perl 6, why not move the grep() into the while()? Because it's only a figurative example and you're supposed to consider the general problem, not nitpick the specific example… But how is that not a general solution? You wanted something where you only have to set the test conditions in one place; what's wrong with that one place being inside the while()? Because readability suffers immensely when ensuring the invariant takes more than a single short expression. You have to break the loop condition out over several indented lines. Not pretty. * Eirik Berg Hanssen [EMAIL PROTECTED] [2008-12-03 22:30]: I think Perl 5 will always allow: while ( doSomething(), someCondition() ) { doSomethingElse(); } I also think Perl 6 will always allow: while ( doSomething(); someCondition() ) { doSomethingElse(); } ... but don't quote me on that. Unless I'm right. ;-) The Perl 6 version of the two is more bearable, because neither do you need a `do{}` bracket nor do comma precendence issues force you to strew parens the expressions. But as I wrote above, this breaks down as soon as you need to do a non-trivial amount of work to ensure the invariant. * Jon Lang [EMAIL PROTECTED] [2008-12-03 22:05]: I suspect that the difficulty with the while(1) version was the kludgey syntax; the loop syntax that you describe does the same thing (i.e., putting the test in the middle of the loop block instead of at the start or end of it), but in a much more elegant manner. The only thing that it doesn't do that a more traditional loop construct manages is to make the loop condition stand out visually. There’s no real difference between `while(1)` and `loop` to me. I don’t like C’s `for(;;)`, but both the Perl 5 and 6 idioms are equally fine with me. The problem I have is that the number of iterations is not indeterminate; there is a set amount of work to be complete, whereupon the loop will terminate. Contrast to the event loop in a GUI, f.ex., where the termination of the loop is an exceptional event, and the loop runs for as long as the app is running. This is much like being able to have statement modifier forms of conditionals and loops: I want to put emphasis on what matters. When I see `while ( @stuff )` that means to me that [EMAIL PROTECTED] is expected to run out as a consequence of the loop body operating on it. When I say `while (1)` I generally intend to say that I don’t expect the loop to terminate any time soon, although of course some uncommon condition might require termination. * David Green [EMAIL PROTECTED] [2008-12-03 22:00]: On 2008-Dec-3, at 12:38 pm, Mark J. Reed wrote: I think the cleanest solution is the coy one. Me too. I don't think having the condition in the middle of the block is necessarily a bad thing -- that's how the logic is actually working, after all. Fake conditions like while(1) are kind of ugly, but P6 has loop, and you can always make it stand out more: loop { doSomething(); #CHECK OUR LOOP CONDITION! last unless someCondition; doSomethingElse(); } See above. When each iteration of the loop reduces some finite quantity, I want to use a check for that quantity as the loop condition, to point out that this is the purpose of the loop: to finish a particular pile of work and terminate. This is in contrast to a loop which reacts to an infinite stream of input of whatever sort. Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/
Re: Support for ensuring invariants from one loop iteration to the next?
* Mark J. Reed [EMAIL PROTECTED] [2008-12-03 20:30]: OK, so let's look at the general problem. The structure is this: doSomething(); while (someCondition()) { doSomethingElse(); doSomething(); } ...and you want to factor out the doSomething() call so that it only has to be specified once. Is that correct, Aristotle? Yes. The gotcha is that the first doSomething() is unconditional, while the first doSomethingElse() should only happen if the loop condition is met (which means just moving the test to the end of the block doesn't solve the problem). Exactly. Overall, the goal is to ensure that by the end of the loop the program is in the state of having just called doSomething(), whether the loop runs or not - while also ensuring that the program is in that state at the top of each loop iteration. It’s not a goal in itself. It’s just a necessity: you cannot test the loop condition without ensuring the invariant, so whether or not the loop runs is irrelevant, you have to run it once before you can know whether the loop will run at all. It does seem like a closure trait sort of thing, but I don't think it's currently provided by the p6 spec. I don’t see anything suitable there either. And while it does seems like a closure trait, that seems somewhat problematic in that the order of evaluation is weird when compared to other closure traits, which I suppose is what led you to declare the “coy” solution as the most natural. I am trying to think of a good block structure to capture these semantics spatially and not currently coming up with anything very good. * Mark J. Reed [EMAIL PROTECTED] [2008-12-03 20:40]: We can guarantee it's set at the top of each loop iteration with ENTER, but that doesn't get run if the loop never runs. We can guarantee it's set at the end of the loop with LAST, but that also doesn't get run if the loop never runs, and doesn't take care of the first iteration. For the purposes of this particular problem, there isn’t even much difference between those two. * Patrick R. Michaud [EMAIL PROTECTED] [2008-12-03 21:10]: Perhaps PRE ... ? while (someCondition()) { PRE { doSomething(); } doSomethingElse(); } The problem is, doSomething() has to be run *prior* to *any* loop condition check – including the very first. PRE (or ENTER) can’t do that. Or, if you wanted to be sure that doSomething() is always called at least once: repeat { PRE { doSomething(); } doSomethingElse(); } while someCondition(); That will run doSomething() once unconditionally. That’s not what I’m after. -- *AUTOLOAD=*_;sub _{s/(.*)::(.*)/print$2,(,$\/, )[defined wantarray]/e;$1} Just-another-Perl-hack; #Aristotle Pagaltzis // http://plasmasturm.org/
Re: Support for ensuring invariants from one loop iteration to the next?
* David Green [EMAIL PROTECTED] [2008-12-03 22:00]: FIRST{} can do something on only the first iteration through the loop, but there's no NOT-FIRST block to do something on the second and subsequent iterations. Is there an elegant way to do something on all but the first loop? Not with a closure trait and without a flag, which I guess does not count as elegant. In Template Toolkit this is nice insofar as that the loop iterator is available as an object in a variable, so you can say IF loop.first ; ... ; END ; but equally IF NOT loop.first ; ... ; END ; and similarly you can say IF NOT loop.last ; ... ; END ; to do something on all iterations but the ultimate. Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/
Support for ensuring invariants from one loop iteration to the next?
Hi all, I occasionally find myself annoyed at having to do something like this (I use Perl 5 vernacular, but it actually crops up in every single language I have ever used): my $i; @stuff = grep !$_-valid, @stuff; while ( @stuff ) { $_-do_something( ++$i ) for @stuff; @stuff = grep !$_-valid, @stuff; } Here, both the `while` condition and the `for` iteration assume that [EMAIL PROTECTED] will contain only valid elements. Since I don’t know whether this is initially the case, I have to repeat the statement both before the loop and at its bottom. There is no good way to rearrange this in the general case. The only way to improve it at all is some variant on this: my $i; while (1) { @stuff = grep !$_-valid, @stuff; last if not @stuff; $_-do_something( ++$i ) for @stuff; } Here I am forced to give up the formal loop conditional and bury the termination condition somewhere in the middle of the loop body. The code doesn’t exactly lie now, but it’s more coy about its intent than necessary. Does Perl 6 have some mechanism so I could write it along the following obvious lines? my $i; while ( @stuff ) { $_-do_something( ++$i ) for @stuff; } # plus some way of attaching this fix-up just once { @stuff = grep !$_-valid, @stuff } Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/
Re: Support for ensuring invariants from one loop iteration to the next?
On Dec 3, 2008, at 7:14 AM, Aristotle Pagaltzis wrote: --snip-- Does Perl 6 have some mechanism so I could write it along the following obvious lines? my $i; while ( @stuff ) { $_-do_something( ++$i ) for @stuff; } # plus some way of attaching this fix-up just once { @stuff = grep !$_-valid, @stuff } In Perl 5 or Perl 6, why not move the grep() into the while()? my $i; while ( @stuff = grep !$_-valid, @stuff ) { $_-do_something( ++$i ) for @stuff; } Perl 5 example: $ perl -wle '@z=qw(a bb ccc); while (@z = grep { length($_) 4 } @z) { print @z; $_ .= . for @z }' a bb ccc a. bb. a.. By the way, your use of '!$_-valid' instead of '$_-valid' sounds backwards when compared with your text ...assume that [EMAIL PROTECTED] will contain only valid elements. -- Hope this helps, Bruce Gray (Util of PerlMonks)
Re: Support for ensuring invariants from one loop iteration to the next?
* Bruce Gray [EMAIL PROTECTED] [2008-12-03 18:20]: In Perl 5 or Perl 6, why not move the grep() into the while()? Because it’s only a figurative example and you’re supposed to consider the general problem, not nitpick the specific example… Regards, -- Aristotle Pagaltzis // http://plasmasturm.org/
Re: Support for ensuring invariants from one loop iteration to the next?
Aristotle Pagaltzis wrote: * Bruce Gray [EMAIL PROTECTED] [2008-12-03 18:20]: In Perl 5 or Perl 6, why not move the grep() into the while()? Because it's only a figurative example and you're supposed to consider the general problem, not nitpick the specific example… But how is that not a general solution? You wanted something where you only have to set the test conditions in one place; what's wrong with that one place being inside the while()? -- Jonathan Dataweaver Lang
Re: Support for ensuring invariants from one loop iteration to the next?
OK, so let's look at the general problem. The structure is this: doSomething(); while (someCondition()) { doSomethingElse(); doSomething(); } ...and you want to factor out the doSomething() call so that it only has to be specified once. Is that correct, Aristotle? The gotcha is that the first doSomething() is unconditional, while the first doSomethingElse() should only happen if the loop condition is met (which means just moving the test to the end of the block doesn't solve the problem). IFF the doSomething() can be reasonably combined with the conditional test, then Bruce's solution works, but that won't necessarily be the case in general. Overall, the goal is to ensure that by the end of the loop the program is in the state of having just called doSomething(), whether the loop runs or not - while also ensuring that the program is in that state at the top of each loop iteration. It does seem like a closure trait sort of thing, but I don't think it's currently provided by the p6 spec.
Re: Support for ensuring invariants from one loop iteration to the next?
On Wed, Dec 3, 2008 at 2:26 PM, Mark J. Reed [EMAIL PROTECTED] wrote: Overall, the goal is to ensure that by the end of the loop the program is in the state of having just called doSomething(), whether the loop runs or not - while also ensuring that the program is in that state at the top of each loop iteration. ... including the first, just to point out the problem. We can guarantee it's set at the top of each loop iteration with ENTER, but that doesn't get run if the loop never runs. We can guarantee it's set at the end of the loop with LAST, but that also doesn't get run if the loop never runs, and doesn't take care of the first iteration. It does seem like a closure trait sort of thing, but I don't think it's currently provided by the p6 spec. I think the cleanest solution is the coy one. This works in pugs: do { doSomething(); if (someCondition()) { doSomethingElse(); redo; } } But I'm not sure that redo in a do block is supposed to be allowed. If not, you have to do something like this: loop { doSomething(); if (someCondition()) { doSomethingElse(); } else { last; } } -- Mark J. Reed [EMAIL PROTECTED]
Re: Support for ensuring invariants from one loop iteration to the next?
On Wed, Dec 03, 2008 at 02:26:57PM -0500, Mark J. Reed wrote: OK, so let's look at the general problem. The structure is this: doSomething(); while (someCondition()) { doSomethingElse(); doSomething(); } ...and you want to factor out the doSomething() call so that it only has to be specified once. ... It does seem like a closure trait sort of thing, but I don't think it's currently provided by the p6 spec. Perhaps PRE ... ? while (someCondition()) { PRE { doSomething(); } doSomethingElse(); } Or, if you wanted to be sure that doSomething() is always called at least once: repeat { PRE { doSomething(); } doSomethingElse(); } while someCondition(); In the original post, this would result in: my $i; repeat { PRE { @stuff = grep { !.valid }, @stuff } .do_something( ++$i ) for @stuff; } while @stuff; I don't know if the PRE block automatically throws an exception that needs to be caught, or if it simply prevents the block from being run. I'm guessing it throws an exception, but if so that should be catchable w/o too much difficulty. Pm
Re: Support for ensuring invariants from one loop iteration to the next?
On Wed, Dec 3, 2008 at 3:05 PM, Patrick R. Michaud [EMAIL PROTECTED] wrote: It does seem like a closure trait sort of thing, but I don't think it's currently provided by the p6 spec. Perhaps PRE ... ? Isn't PRE { blah; } just short for ENTER { die unless blah; } ? It still has the problem that it won't get executed if the loop body never is. while (someCondition()) { PRE { doSomething(); } doSomethingElse(); } Might never call doSomething(). Or, if you wanted to be sure that doSomething() is always called at least once: repeat { PRE { doSomething(); } doSomethingElse(); } while someCondition(); Calls doSomethingElse() even if someCondition() is initially false (violates the gotcha I mentioned). Incidentally, I was just trying to clarify what I think Aristotle was asking for, and am not saying it's needed. I suspect this might be too specific a case to worry about, and I'm willing to settle for the solution in my last message (using an if inside a do or loop block). -- Mark J. Reed [EMAIL PROTECTED]
Re: Support for ensuring invariants from one loop iteration to the next?
oops make that last if !someCondition(); -- Mark Biggar [EMAIL PROTECTED] [EMAIL PROTECTED] [EMAIL PROTECTED] -- Original message -- From: [EMAIL PROTECTED] loop { doSomething(); next if someCondition(); doSomethingElse(); } -- Mark Biggar [EMAIL PROTECTED] [EMAIL PROTECTED] [EMAIL PROTECTED] -- Original message -- From: Mark J. Reed [EMAIL PROTECTED] OK, so let's look at the general problem. The structure is this: doSomething(); while (someCondition()) { doSomethingElse(); doSomething(); } ...and you want to factor out the doSomething() call so that it only has to be specified once. Is that correct, Aristotle? The gotcha is that the first doSomething() is unconditional, while the first doSomethingElse() should only happen if the loop condition is met (which means just moving the test to the end of the block doesn't solve the problem). IFF the doSomething() can be reasonably combined with the conditional test, then Bruce's solution works, but that won't necessarily be the case in general. Overall, the goal is to ensure that by the end of the loop the program is in the state of having just called doSomething(), whether the loop runs or not - while also ensuring that the program is in that state at the top of each loop iteration. It does seem like a closure trait sort of thing, but I don't think it's currently provided by the p6 spec.
Re: Support for ensuring invariants from one loop iteration to the next?
On Wed, Dec 3, 2008 at 3:42 PM, [EMAIL PROTECTED] wrote: loop { doSomething(); next if someCondition(); doSomethingElse(); } That loops forever, doesn't it? But I think this works: loop { doSomething(); last unless someCondition(); doSomethingElse(); } -- Mark J. Reed [EMAIL PROTECTED]
Re: Support for ensuring invariants from one loop iteration to the next?
On Wed, Dec 3, 2008 at 3:44 PM, Mark J. Reed [EMAIL PROTECTED] wrote: On Wed, Dec 3, 2008 at 3:42 PM, [EMAIL PROTECTED] wrote: loop { doSomething(); next if someCondition(); doSomethingElse(); } That loops forever, doesn't it? But I think this works: loop { doSomething(); last unless someCondition(); doSomethingElse(); } That is, of course, merely the while(1) version from Aristotle's original message rewritten with Perl 6's loop keyword. As I said, I'm OK with that, personally, but it's clearly not what he's looking for. -- Mark J. Reed [EMAIL PROTECTED]
Re: Support for ensuring invariants from one loop iteration to the next?
Mark J. Reed wrote: Mark J. Reed wrote: loop { doSomething(); last unless someCondition(); doSomethingElse(); } That is, of course, merely the while(1) version from Aristotle's original message rewritten with Perl 6's loop keyword. As I said, I'm OK with that, personally, but it's clearly not what he's looking for. But maybe it is. I suspect that the difficulty with the while(1) version was the kludgey syntax; the loop syntax that you describe does the same thing (i.e., putting the test in the middle of the loop block instead of at the start or end of it), but in a much more elegant manner. The only thing that it doesn't do that a more traditional loop construct manages is to make the loop condition stand out visually. -- Jonathan Dataweaver Lang
Re: Support for ensuring invariants from one loop iteration to the next?
Mark J. Reed [EMAIL PROTECTED] writes: OK, so let's look at the general problem. The structure is this: doSomething(); while (someCondition()) { doSomethingElse(); doSomething(); } ...and you want to factor out the doSomething() call so that it only has to be specified once. I think Perl 5 will always allow: while ( doSomething(), someCondition() ) { doSomethingElse(); } I also think Perl 6 will always allow: while ( doSomething(); someCondition() ) { doSomethingElse(); } ... but don't quote me on that. Unless I'm right. ;-) Eirik -- Statistics means never having to say you're certain.