Re: Support for ensuring invariants from one loop iteration to the next?

2008-12-18 Thread David Green

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?

2008-12-18 Thread Aristotle Pagaltzis
* 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?

2008-12-18 Thread Larry Wall
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?

2008-12-18 Thread Jon Lang
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?

2008-12-17 Thread Aristotle Pagaltzis
* 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?

2008-12-16 Thread David Green

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?

2008-12-16 Thread Timothy S. Nelson

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?

2008-12-16 Thread Jon Lang
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?

2008-12-16 Thread Timothy S. Nelson

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?

2008-12-16 Thread David Green

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?

2008-12-06 Thread John Macdonald
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?

2008-12-06 Thread Aristotle Pagaltzis
* 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?

2008-12-05 Thread David Green

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?

2008-12-05 Thread David Green

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?

2008-12-04 Thread Aristotle Pagaltzis
* [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?

2008-12-04 Thread Aristotle Pagaltzis
* 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?

2008-12-04 Thread Aristotle Pagaltzis
* 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?

2008-12-03 Thread Aristotle Pagaltzis
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?

2008-12-03 Thread Bruce Gray




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?

2008-12-03 Thread Aristotle Pagaltzis
* 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?

2008-12-03 Thread Jon Lang
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?

2008-12-03 Thread Mark J. Reed
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?

2008-12-03 Thread Mark J. Reed
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?

2008-12-03 Thread Patrick R. Michaud
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?

2008-12-03 Thread Mark J. Reed
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?

2008-12-03 Thread mark . a . biggar
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?

2008-12-03 Thread Mark J. Reed
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?

2008-12-03 Thread Mark J. Reed
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?

2008-12-03 Thread Jon Lang
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?

2008-12-03 Thread Eirik Berg Hanssen
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.