5

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.

Community
  • 1
  • 1
yusuf
  • 3,591
  • 8
  • 45
  • 86

4 Answers4

11

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.

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • Tomas, the sequence of my functions are important. For instance, I have to use the functions in if - else first, then I have to write my while loop. Your solution is perfect, but if I implement this, the sequence of my events are changing. For instance, I have to call MoveSensor() function before calling CalibrateSensorPosition(). How can we implement the approach according to the sequence? – yusuf Jan 03 '15 at 13:46
  • 1
    You can define this as local function and call it from the right place in your main function. I believe my snippet preserves your order of calls... – Tomas Petricek Jan 03 '15 at 14:39
6

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()
Gus
  • 25,839
  • 2
  • 51
  • 76
2

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()
yusuf
  • 3,591
  • 8
  • 45
  • 86
  • 2
    Yes, using a (mutable) flag will do the job as well. But you don't need `= true` inside the while condition, it's redundant. You can write just `while flag do` – Gus Jan 03 '15 at 14:54
  • 1
    Not downvoting, but I would not consider mutability "fine" when other, more idiomatic, options are available and just as easy. I wouldn't let this pass a code review at work. ;-] – ildjarn Jan 04 '15 at 03:28
  • 2
    I agree with @ildjarn except that I would accept it momentarily if it's a translation from C# code or another language. Once the translation is finished and fully tested and accepted I would consider refactoring to more f#-ish style and remove unnecessary mutables. – Gus Jan 04 '15 at 08:23
  • 1
    I think this portrait the intent of the code with more clarity. Mutability is ok when is localized and contained. – mamcx Feb 19 '16 at 19:10
0

I think that an easy way is when it happen that you need to have a "break" in a loop then you just make sure that the loop terminate.

an example of this could be that if we have a while loop that look like this

while i < upperlimit do
   if a
   then break
YoungHobbit
  • 13,254
  • 9
  • 50
  • 73
kam
  • 590
  • 2
  • 11