Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# breaking from while loop in complex statements

Tags:

f#

I have such a function:

let ScanColors() =
    for i in 1..54 do
        let mutable c = Unchecked.defaultof<string>

        if (i = 9) then 
            c <- "U - WHITE"
        else
            if (i <> 0 && i%9 = 0) then 
                MoveSensor(SensorPos.THIRD)
            else
                MoveSensor(
                    match ((i - (i/9)*9)%2 <> 0) with 
                        | true -> SensorPos.SECOND
                        | false -> SensorPos.FIRST)

            while (true) do
                c <- ScanColor()
                if (c = "ERR") then
                    CalibrateSensorPosition()
                else
                   break
            ResetSensorPosition()

in this function, in the whilestatement, I cannot use break, because as you know, break is not used in F#. I was looking for alternatives for break, and I saw this link:

F# break from while loop

But to be honest, I couldn't be sure whether this solution suits with my problem.

like image 715
yusuf Avatar asked Jan 03 '15 13:01

yusuf


3 Answers

Sadly F# does not support break. There are various fairly complicated ways to deal with this (like this recent one or my computation builder), but those have disadvantages and make your code fairly complex.

The general way to deal with this is to rewrite the code using recursion - this will typically compile to the same IL as what you would write in C# using break and continue.

So, the while block in your snippet could be written as a function that calls itself recursively until the result is not "ERR" and then returns the c:

let rec scanWhileErr () =     
  let c = ScanColor()
  if c = "ERR" then
    CalibrateSensorPosition()
    scanWhileErr()
  else c

And then call this function from the main block:

if (i <> 0 && i%9 = 0) then 
  MoveSensor(SensorPos.THIRD)
else
  MoveSensor(if (i - (i/9)*9)%2 <> 0 then SensorPos.SECOND else SensorPos.FIRST)

c <- scanWhileErr ()
ResetSensorPosition()

Aside, I also changed your match on Booleans into an ordinary if - when you have just two cases and they are Booleans, there is really no point in using match over if.

Also, I kept your mutable variable c, but I suspect that you no longer need it thanks to recursion.

like image 152
Tomas Petricek Avatar answered Nov 13 '22 21:11

Tomas Petricek


Break does not exist in F#, personally I would try to avoid breaks even in C# as there are many alternative/cleaner ways to break a loop.

A simple fix while keeping your imperative code style will be this:

c <- ScanColor()
while (c = "ERR") do
    CalibrateSensorPosition()
    c <- ScanColor()
ResetSensorPosition()

But in F# it can be further compacted to this one-liner:

while (c <- ScanColor(); c = "ERR") do CalibrateSensorPosition()
like image 6
Gus Avatar answered Nov 13 '22 21:11

Gus


Actually, I think this approach is fine, and worked in my case:

        let mutable flag = true
        while (flag = true) do
            c <- ScanColor()
            if (c = "ERR") then
                CalibrateSensorPosition()
            else
               flag <- false
        ResetSensorPosition()
like image 2
yusuf Avatar answered Nov 13 '22 21:11

yusuf