Below is a piece of code shown and doubts are regarding the implementation of loops
C := character'last; --'// SO code colorizer hack
I := 1;
K : loop
Done := C = character'first; --'
Count2 := I;
Exit K when Done;
C := character'pred(c); --'
I := I + 1;
end loop K;
Can anyone please tell me what does 'K' stands for.I guess its not a variable.How does 'K' control the execution of the loop?
K is the name of the loop. The end loop and Exit statements refer to that name, to make it clear what loop is being exited.
The Ada Reference Manual calls it a "loop_statement_identifier".
As noted, K is the loop's label. It allows you to identify a particular loop to aid readability, and also to selectively exit a specific loop from a set of nested enclosing ones (i.e. being a "goto"...shhh! :-)
Here's a contrived example (not compiled checked):
S : Unbounded_String;
F : File_Type;
Done_With_Line : Boolean := False;
All_Done : Boolean := False;
begin
Open(F, In_File, "data_file.dat");
File_Processor:
while not End_Of_File(F) loop
S := Get_Line(F);
Data_Processor:
for I in 1 .. Length(S) loop
Process_A_Character
(Data_Char => Element(S, I), -- Mode in
Line_Done => Done_With_Line, -- Mode out
Finished => All_Done); -- Mode out
-- If completely done, leave the outermost (file processing) loop
exit File_Processor when All_Done;
-- If just done with this line of data, go on to the next one.
exit Data_Processor when Done_With_Line;
end loop;
end loop File_Processor;
Close(F);
end;
K is essentially the name of the loop. The exit k tells the code to stop looping and go to the next statement after loop k ends.
You usually don't need to name loops, as you can just say exit and it will exit the enclosing loop. However, if you have a loop nested inside another loop, and you'd like to exit not the one immediately around the exit statement, but the outermost one, then doing something like this may be required.
K is a label that names the loop. Wow, it has been a long time since I've seen any Ada...
Related
A colleague and I were trying to figure out a way of doing the equivalent of a "continue" statement within a VBScript "For/Next" loop.
Everywhere we looked we found people had no way to do this in VBScript without having nasty nestings, which is not an option for us since it is a quite big loop.
We came out with this idea. Would it work just as a "continue(to next iteration)"? Does anyone have any better workaround or improvement suggestion?
For i=1 to N
For workaroundloop = 1 to 1
[Code]
If Condition1 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[...]
Next
Next
Thanks for your comments
Your suggestion would work, but using a Do loop might be a little more readable.
This is actually an idiom in C - instead of using a goto, you can have a do { } while (0) loop with a break statement if you want to bail out of the construct early.
Dim i
For i = 0 To 10
Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False
Next
As crush suggests, it looks a little better if you remove the extra indentation level.
Dim i
For i = 0 To 10: Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False: Next
A solution I decided on involved the use of a boolean variable to track if the for loop should process its instructions or skip to the next iteration:
Dim continue
For Each item In collection
continue = True
If condition1 Then continue = False End If
If continue Then
'Do work
End If
Next
I found the nested loop solutions to be somewhat confusing readability wise. This method also has its own pitfalls since the loop doesn't immediately skip to the next iteration after encountering continue. It would be possible for a later condition to reverse the state of continue. It also has a secondary construct within the initial loop, and requires the declaration of an extra var.
Oh, VBScript...sigh.
Also, if you want to use the accepted answer, which isn't too bad readability wise, you could couple that with the use of : to merge the two loops into what appears to be one:
Dim i
For i = 0 To 10 : Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False : Next
I found it useful to eliminate the extra level of indentation.
One option would be to put all the code in the loop inside a Sub and then just return from that Sub when you want to "continue".
Not perfect, but I think it would be less confusing that the extra loop.
I use to use the Do, Loop a lot but I have started using a Sub or a Function that I could exit out of instead. It just seemed cleaner to me. If any variables you need are not global you will need to pass them to the Sub also.
For i=1 to N
DoWork i
Next
Sub DoWork(i)
[Code]
If Condition1 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[...]
End Sub
We can use a separate function for performing a continue statement work. suppose you have following problem:
for i=1 to 10
if(condition) then 'for loop body'
contionue
End If
Next
Here we will use a function call for for loop body:
for i=1 to 10
Call loopbody()
next
function loopbody()
if(condition) then 'for loop body'
Exit Function
End If
End Function
loop will continue for function exit statement....
I've always used an Do While loop. This works with both For type loops.
For iIndex = 0 to 100
Do
If bCondition then Exit Do
...
Loop While False
Next
IMHO, this just looks clean.
I just saw Crush's answer, at the bottom. Sorry for the duplicate answer.
Implement the iteration as a recursive function.
Function Iterate( i , N )
If i == N Then
Exit Function
End If
[Code]
If Condition1 Then
Call Iterate( i+1, N );
Exit Function
End If
[Code]
If Condition2 Then
Call Iterate( i+1, N );
Exit Function
End If
Call Iterate( i+1, N );
End Function
Start with a call to Iterate( 1, N )
Try use While/Wend and Do While / Loop statements...
i = 1
While i < N + 1
Do While true
[Code]
If Condition1 Then
Exit Do
End If
[MoreCode]
If Condition2 Then
Exit Do
End If
[...]
Exit Do
Loop
Wend
I think you are intended to contain ALL YOUR LOGIC under your if statement. Basically:
' PRINTS EVERYTHING EXCEPT 4
For i = 0 To 10
' you want to say
' If i = 4 CONTINUE but VBScript has no continue
If i <> 4 Then ' just invert the logic
WSH.Echo( i )
End If
Next
This can make the code a bit longer, but some people don't like break or continue anyway.
I am writing a very basic Fortran Code to create the Ising model. However, I am stuck at the very last step - repeat the calculation until the most stable condition is achieved.
do
!Calculation (omitted here)
!Making a decision
if (E1 /= -64) then !not yet stable
if(dE > 0.0) then
call seed
call random_number(prob) ! random generate a number which is 0 <= Prob <= 1
Print *, prob
if(Prob < exp(-dE/T)) then
!do nothing as the flip was made
else
mat(b,c) = -mat(b,c) !flip the sign back, i.e. reject the change; only accept with probability of exp(-dE/T)
end if
else
end if !Since the sign has changed already, if dE<0, the move must be accepted. Therefore no additional move should be taken
else
end do
end if
end do
Apparently, Fortran doesn't like the second last end do statement as I didn't defined do at that particularly. All I want is to exit the do loop once E1 == -64.
In Fortran you can exit a do loop at any time using the exit statement.
do
...
if (condition) exit
end do
If your do loop is labelled, use the label in the exit statement too
outer: do
inner: do
...
if (condition) exit outer
end do inner
end do outer
Fortran 2008 allows the exit statement for other constructs too.
You should be able to use a while loop.
while (E1 [.ne. OR /=] -64) do
[your code]
end do
This requires E1 be updated inside the loop. Without this update, E1 will always not equal -64 and cause an infinite loop. Your code doesn't explicitly show this happening. I assume it does, but it's something to keep in mind.
I have done some searching about how to detect a loop in topological sort, I also finish the coding for the finding a loop, and here is the code:
--print the sort message
IF Kn = 0 THEN
Put("The sorting is complete!!");
RETURN;
ELSE
Put("The Sorting is not complete, loops occur!!");
FOR K IN 1 .. NA LOOP
SortStructure(K).Count:= 0;
END LOOP;
END IF;
-- Find the loop
for K in 1 .. NA loop
P := SortStructure(K).Top;
SortStructure(K).Top := ITN(0);
--when count = 0 and top /= 0, the loop occur
while P /= ITN(0) and then SortStructure(SortElement'Pos(P.suc)).count= 0 loop
SortStructure(SortElement'Pos(P.suc)).count:= k;
IF P /= Itn(0) THEN
P := P.Next;
END IF;
END LOOP;
END LOOP;
--use K determine a part of the loop
K:=1;
WHILE Sortstructure(K).Count= 0 LOOP
K:= K+1;
END LOOP;
--Mark the loop
LOOP
Sortstructure(K).Top := ITN(1);
K:= Sortstructure(K).Count;
EXIT WHEN SortStructure(K).Top /= ITN(0);
END LOOP;
--Print the loop
Put_Line("The loop is: ");
WHILE SortStructure(K).Top /= ITN(0) LOOP
--SortElement'Val(K) will return the value of K, make this also work for Enumeration
Put(SortElement'Val(K));
Put(", ");
SortStructure(K).Top := ITN(0);
K:= SortStructure(K).Count;
END LOOP;
Put(SortElement'Val(K));
New_Line;
This code starts from printing the message if there is a loop occurred, then mark the beginning of the loop and the end of the loop then print it. It works well for detect single loop, but how to make this can detect multiple loops and print them?
For example:Given the relations (format "Pre < Suc"):
1<2, 2<3, 3<1 (one loop), 1<4, 4<3 (second loop).
Any ideas would be appreciated.
I am not sure if topological sorting will help you detecting all cycles. It definitely helps you in testing whether the graph is acyclic or not.
Why you do not simply run DFS over the graph and look for back edges. Every time you encounter a back edge, you print the cycle path. The printing task is kind of tricky but I believe is doable ( see this )
I would think , you would go like All path problem. If topological sort is what you want to do for detecting multiple cycles, whenever you detect a cycle, add the current stack to a list and continue with next available node , and go up the edge recursively.
I am trying to use the 'Last attribute with a 2D array in Ada, but I can't seem to find the correct syntax to do so.
I know that if I have a 1D array/vector I can use A'last or A'last(n) where n is the nth dimension. But if I do the following
type UnconstrainedArray_2D is array (Integer range <>, Integer range <>) of Integer;
function temp(tempIn : in Integer;
Table : in UnconstrainedArray_2D) return Integer is
tempTable : UnconstrainedArray_2D(0..tempIn, 0..tempIn);
begin
for i in 0..tempTable'last(1) loop
for j in 0..tempTable'last(2) loop
tempTable(i, j) := Table(i,j);
end loop;
end loop;
end temp;
I get the following compile time error:
Storage_Error stack overflow (or erroneous memory access)
So what am I doing wrong?
I am using GNAT Pro 6.4.1 on Linux.
I'd be very surprised if you got a compile-time Storage_Error on that code.
I've grabbed a copy of your code and modified it as follows; it compiles without error using GNAT (gcc-4.4):
procedure Array_2D is
type UnconstrainedArray_2D is array (Integer range <>, Integer range <>) of Integer;
function temp(tempIn : in Integer;
Table : in UnconstrainedArray_2D) return Integer is
tempTable : UnconstrainedArray_2D(0..tempIn, 0..tempIn);
begin
for i in 0..tempTable'last(1) loop
for j in 0..tempTable'last(2) loop
tempTable(i, j) := Table(i,j);
end loop;
end loop;
return 42; -- added this
end temp;
begin
null;
end Array_2D;
(Note that I had to add the missing return statement in temp.)
Your syntax for the 'Last attribute (not "command") is correct, but since Ada arrays can have arbitrary lower and upper bounds, it's better to use the 'Range attribute instead:
for i in tempTable'Range(1) loop
for j in tempTable'Range(2) loop
tempTable(i, j) := Table(i,j);
end loop;
end loop;
As for the Storage_Error exception, that could easily happen at run time (not compile time) if you call your temp function with a very large value for tempIn. Remember that it has to allocate enough space to hold tempIn**2 Integer objects. Presumably you've also created another UnconstrainedArray_2D object to be passed in as the Table parameter.
It's conceivable that the compiler itself could die with a Storage_Error exception, but I don't see anything in your code that might cause that.
Show us a complete (but small) program that demonstrates the problem you're having, along with the exact (copy-and-pasted) error message. Please distinguish clearly between compile-time and run-time errors.
Your tempTable might have a range of 0..tempIn, but you don't know what range your Table has.. They could be of different length, too.
You would have to check that the length is the same and then use relative indices, like this:
function temp(tempIn : in Integer;
Table : in UnconstrainedArray_2D) return Integer is
tempTable : UnconstrainedArray_2D(0..tempIn, 0..tempIn);
begin
if tempTable'Length (1) /= Table'Length (1) or else
tempTable'Length (2) /= Table'Length (2)
then
raise Constraint_Error; -- or something else
end if;
for i in 0 .. tempTable'Length (1) - 1 loop
for j in 0 .. tempTable'Length (2) - 1 loop
tempTable(tempTable'First (1) + i, tempTable'First (2) + j) :=
Table(Table'First (1) + i, Table'First (2) + j);
end loop;
end loop;
end temp;
that way it is ensured that both tables are same length and all indices are valid.
If your tempTable is allowed to be smaller than Table, simply adjust the length check to >. The indices would still be valid.
I don't see an actual value for tempIn set. If the value for tempIn coming into the function temp has not been properly initialized or explicitly set, then the value in tempIn could be anything and probably not something you would like.
I was thinking of a default value. (probably shouldn't post when I am not feeling well :-)
Is there any programming language that has a do-until loop?
Example:
do
{
<statements>
}
until (<condition>);
which is basically equivalent to:
do
{
<statements>
}
while (<negated condition>);
NOTE: I'm looking for post-test loops.
Ruby has until.
i=0
begin
puts i
i += 1
end until i==5
VBA!
Do-Until-Loop
Do-Loop-Until
Although I think quite a number of people here would doubt if it is a real language at all, but well, BASIC is how Microsoft started (quite weak argument for many, I know)...
It is possible in VB.Net
bExitFromLoop = False
Do
'Executes the following Statement
Loop Until bExitFromLoop
It is also possible in SDF-P on BS2000 (Fujitsu/Siemens Operating System)
/ DECLARE-VARIABLE A
/ DECLARE-VARIABLE SWITCH-1(TYPE=*BOOLEAN)
/ SET-VARIABLE A = 5
/ SET-VARIABLE SWITCH-1 = ON
/ REPEAT
/ A = A + 10
/ IF (A > 50)
/ SET-VARIABLE SWITCH-1 = OFF
/ END-IF
/ UNTIL (SWITCH-1 = OFF)
/ SHOW-VARIABLE A
A = 55
Is is also possible is C or C++ using a macro that define until
Example (definition):
#define until(cond) while(!(##cond))
Example (utilisation):
int i = 0;
do {
cout << i << "\n";
i++;
} until(i == 5);
In VB we can find something like:
Reponse = InputBox("Please Enter Pwd")
Do Until Reponse = "Bob-pwr148" ...
Eiffel offers you an until loop.
from
x := 1
until
x > 100
loop
...
end
There is also an "across" loop as well. Both are very powerful and expressive.
The design of this loop has more to offer. There are two more parts to its grammar that will help us resolve two important "correctness" problems.
Endless loop protection.
Iteration failure detection.
Endless Loop Protection
Let's modify our loop code a little by adding a loop variant.
from
x := 1
v := 1_000
until
x > 100
variant
v
loop
...
v := v - 1
end
The loop variant is (essentially) a count-down variable, but not just any old variable. By using the variant keyword, we are telling the compiler to pay attention to v. Specifically, the compiler is going to generate code that watchdogs the v variable for two conditions:
Does v decrease with each iteration of the loop (are we counting down). It does no good to try and use a count-down variable if it is (in fact) not counting down, right? If the loop variant is not counting down (decreasing by any amount), then we throw an exception.
Does v ever reach a condition of less than zero? If so, then we throw an exception.
Both of these work together through the compiler and variant variable to detect when and if our iterating loop fails to iterate or iterates too many times.
In the example above, our code is communicating to us a story that it expects to iterate zero to 1_000 times, but not more. If it is more, then we stop the loop, which leaves us to wonder: Do we really have cases were we iterate more than 1_000 times, or is there something wrong that our condition is failing to become True?
Loop Invariant
Now that we know what a loop variant is, we need to understand what a loop invariant is.
The invariant is a set of one or more Boolean conditions that must hold True after each iteration through the loop. Why do we want these?
Imagine you have 1_000_000 iterations and one of them fails. You don't have time to walk through each iteration, examining it to see it is okay or not. So, you create a set of one or more conditions that are tested upon completion of each iteration. If the one or all of the conditions fail, then you know precisely which iteration (and its deterministic state) is causing the problem!
The loop invariant might look something like:
from
x := 1
y := 0
v := 1_000
invariant
y = x - 1
until
x > 100
variant
v
loop
...
x := x + 1
y := y + 1
v := v - 1
end
In the example above, y is trailing x by 1. We expect that after each iteration, y will always be x - 1. So, we create a loop invariant using the invariant keyword that states our Boolean assertion. If y fails to be x - 1, the loop will immediately throw an exception and let us know precisely which iteration has failed to keep the assertion True.
CONCLUSION
Our loop is now quite tight and secure—well guarded against failure (bugs, errors).