Why does my while loop not terminate in this functional language? - arrays

I'm trying to build a standard ML program using both imperative and functional concepts, and write the contents to a file. But my while loop doesn't seem to terminate and instead prints the same value continuously.
fun writeImage image filename =
let val ap = TextIO.openOut filename
val (w,h) = size image
val row = ref 0
val stringToWrite = "";
in
while !row < h do
TextIO.output(ap,"A");
row := !row + 1;
TextIO.closeOut ap
end;
If I remove the first line after the while loop, the loop terminates. But if I include TextIO.output(ap,"A");, it doesn't. Why is this the case?

Let's write your program with correct indentation, and then it becomes clear where the mistake is:
...
while !row < h do
TextIO.output(ap,"A");
row := !row + 1;
TextIO.closeOut ap
...
You loop forever because the increment is outside of the body of the loop.
You intended to write this:
...
while !row < h do (
TextIO.output(ap,"A");
row := !row + 1
);
TextIO.closeOut ap
...
right?
I have long made a study of how people come to make mistakes when programming. I am curious to know how you came to make this mistake. If you believed that ; binds stronger than while then why did you believe that the TextIO.closeOut ap was after the loop? Surely if your belief was that the ; binds the increment to the loop then the ; should bind it to the loop as well. Did you perhaps think that ML is a language like Python, where the looping constructs use the whitespace as a guide to the extent of the body?
What are your beliefs about ; in ML more generally? Do you think of ; as a statement terminator, as it is in C-like languages? Or do you think of it as an infix sequencing operation on side-effecting expressions?
What was your thought process here, and how could the tooling have made it easier for you to solve your problem without having to ask for help?

Related

How would you write the equivalent of this C++ loop in Rust

Rust's for loops are a bit different than those in C-style languages. I am trying to figure out if I can achieve the same result below in a similar fashion in Rust. Note the condition where the i^2 < n.
for (int i = 2; i * i < n; i++)
{
// code goes here ...
}
You can always do a literal translation to a while loop.
let mut i = 2;
while i * i < n {
// code goes here
i += 1;
}
You can also always write a for loop over an infinite range and break out on an arbitrary condition:
for i in 2.. {
if i * i >= n { break }
// code goes here
}
For this specific problem, you could also use take_while, but I don't know if that is actually more readable than breaking out of the for loop. It would make more sense as part of a longer chain of "combinators".
for i in (2..).take_while(|i| i * i < n) {
// code goes here
}
The take_while suggestion from zwol's answer is the most idiomatic, and therefore usually the best choice. All of the information about the loop is kept together in a single expression instead of getting mixed into the body of the loop.
However, the fastest implementation is to precompute the square root of n (actually a weird sort of rounded-down square root). This lets you avoid doing a comparison every iteration, since you know this is always the final value of i.
let m = (n as f64 - 0.5).sqrt() as _;
for i in 2 ..= m {
// code goes here
}
As a side note, I tried to benchmark these different loops. The take_while was the slowest. The version I just suggested always reported 0 ns/iter, and I'm not sure if that's just due to some code being optimised to the point of not running at all, or if it really is too fast to measure. For most uses, the difference shouldn't be important though.
Update: I have learned more Rust since I wrote this answer. This structure is still useful for some rare situations (like when the logic inside the loop needs to conditionally mutate the counter variable), but usually you'll want to use a Range Expression like zwol said.
I like this form, since it keeps the increment at the top of the loop instead of the bottom:
let mut i = 2 - 1; // You need to subtract 1 from the initial value.
loop {
i+=1; if i*i >= n { break }
// code goes here...
}

How to create a matrix in OCaml?

I'am learning OCaml and currently i'am trying to undertand how iteration works in OCaml and how to create a matrix. I want an array 5 x 5 filled with 0. I know there is an issue with shared references so i created a new array at each iteration however iam having issues in other places, specifically at line 6. Let me know of other issues like indentation practices.
open Array;;
let n = ref 5 and i = ref 0 in
let m = Array.make !n 0 in
while !i < !n do
m.(!i) <- Array.make !n 0;;
i := !i + 1;;
done
m;;
You are using ;; too much. Contrary to popular belief, ;; is not part of ordinary OCaml syntax (in my opinion anyway). It's just a special way to tell the toplevel (the REPL) that you want it to evaluate what you've typed so far.
Leave the ;; after open Array. But change all but the last ;; to ; instead.
(Since you reference the Array module by name in your code, which IMHO is good style, you can also just leave out the open Array;; altogether.)
You want the last ;; because you do want the toplevel to evaluate what you've typed so far.
Your syntax error is caused by the fact that your overall code is like this
let ... in
let ... in
while ... do
...
done
m
The while is one expression (in OCaml everything is an expression) and m is another expression. If you want to have two expressions in a row you need ; between them. So you need ; after done.
You also have a type error. When you create m you're creating an array of ints (your given initial value is 0). So you can't make it into a matrix (an array of arrays) later in the code.
Also (not trying to overload you with criticisms :-) this code reads like imperative code. It's not particularly idiomatic OCaml code. In most people's code, using ref is pretty rare. One immediate improvement I see would just be to say let n = 5. You're not changing the value of n anywhere that I see (though maybe this is part of a larger chunk of code). Another improvement would be to use for instead of while.
Finally, you can do this entire operation in one function call:
let n = 5 in
let m = Array.init n (fun i -> Array.make n 0) in
m
Using explicit loops is actually also quite rare in OCaml (at least in my code).
Or you could try this:
let n = 5 in
let m = Array.make_matrix n n 0 in
m

Syntax/concept of a non-iterated loop?

I'm trying to iterate through a loop (any programming language, really, but for this exercise I happen to be using c#) and I was just wondering... what happens when you try to use a loop that doesn't iterate at all (i.e. ...."null"?)
For example:
int x = choose(0,1,2);
for(int i=0;i<x;i++) {
//some stuff
}
Like, what would happen if x gets chosen to be 0? Does it just become a useless for loop on that case? Will my program crash? Is that bad programming practice? etc. etc.
I'm mainly asking because I'm trying to format a concatenated string but only if some array has enough elements. thanks
Well simply put, nothing will happen. A for loop is like an if statement where it checks the condition and repeats while that condition is true.
for(int i=0;i<x;i++)
This is saying:
Initialize i to 0
Check if i is less than the value of x
Increment i at the end of the loop
If x is 0, then the loop will simply not run; it becomes useless.

How to find a loop invariant

I know that the loop invariant is meant to prove the correctness of a problem but i can't quite understand how to come up with one, no matter how trivial the problem is. Here is an example, Can someone point out what are the step i should consider to come up with one. I know that all values that are changing in the loop must be involve in my invariant. Please guide me with this problem, i also have to find the post-condition. An explanation will worth more than an answer; please help.
{M > 0 and N >= 0 }
a = M;
b = N;
k = 1;
while (b > 0) {
if (b % 2 == 0) {
a = a * a;
b = b / 2
} else {
b = b – 1;
k = k * a;
}
}
{ ? ? }
The tricky part about loop invariants is that there is no algorithm (that I'm aware of) that will always guarantee the "correct" answer.
As a start, for the algorithm in your question, try tracing through the program and figure out the goal of the algorithm (Hint: exponents are fun). While tracing keep track of the variables a, b and k.
For example, use M = 2 and N = 1,2,3,.... After a few values of N you'll notice a relationship will start to develop between the variables a, b and k.
Once you figure out the loop invariant the post-condition should be simple to come up with.
Hope this will get the ball rolling for you!
Well, you're going at this a bit backward. As you said, the purpose of the loop invariant is to help you prove the correctness of the program. I guess you didn't write this program -- otherwise you'd know what it was for, and you would have come up with the loop invariant before you wrote the loop, because it's the key to understanding that the loop is correct.
So... what is the program for? How do you know it's correct? The loop invariant will be part of your answer to the second question.
It will sound something like this: At the start and end of every iteration, k=...b.... . After the loop, b==0, so ...., and the program is therefore correct.
I don't want to spell the answer out, because it's probably homework and you'll only learn it if you figure it out yourself.

Appending to array within a loop

I am a SAS programmer learning R.
I have a matrix receivables read from a csv file.
I wish to read the value in the "transit" column, if the value of "id" column of a row is >= 1100000000.
I did this (loop 1):
x = vector()
for (i in 1:length(receivables[,"transit"])){
if(receivables[i,"id"] >= 1100000000){
append(x, receivables[i,"transit"]);
}
}
But, it does not work because after running the loop x is still empty.
>x
logical(0)
However, I was able to accomplish my task with (loop 2):
k=0
x=vector()
for (i in 1:length(receivables[,"transit"])){
if(receivables[i,"id"] >= 1100000000){
k=k+1
x[k] = receivables[i,"transit"]
}
}
Or, with (loop 3):
x = vector()
for (i in 1:length(receivables[,"transit"])){
if(receivables[i,"id"] >= 1100000000){
x <- append(x, receivables[i,"transit"]);
}
}
Why didn't the append function work in the loop as it would in command line?
Actually, to teach me how to fish, what is the attitude/beatitude one must bear in mind when operating functions in a loop as opposed to operating them in command line.
Which is more efficient? Loop 2 or loop 3?
Ok, a few things.
append didn't work in your first attempt because you did not assign the result to anything. In general, R does not work "in place". It is more of a functional language, which means that changes must always be assigned to something. (There are exceptions, but trying to bend this rule too early will get you in trouble.)
A bigger point is that "growing" objects in R is a big no-no. You will quickly start to wonder why anyone could possible use R, because growing objects like this will quickly become very, very slow.
Instead, learn to use vectorized operations, like:
receivables[receivables[,"id"] >= 1100000000,"transit"]

Resources