F#在复杂语句中打破while循环

yus*_*suf 5 f#

我有这样一个功能:

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()
Run Code Online (Sandbox Code Playgroud)

在这个函数中,在while语句中,我不能使用break,因为如你所知,break在F#中没有使用.我正在寻找替代品break,我看到了这个链接:

F#从while循环中断

但说实话,我不能确定这个解决方案是否适合我的问题.

Tom*_*cek 9

可悲的是F#不支持break.有各种相当复杂的方法来处理这个问题(比如最近的一个或我的计算构建器),但这些方法有缺点并且使代码相当复杂.

解决这个问题的一般方法是使用递归重写代码 - 这通常会编译为与在C#中使用break和编写的IL相同的IL continue.

所以,while你的代码片段中的块可以写成一个递归调用自身的函数,直到结果不是"ERR",然后返回c:

let rec scanWhileErr () =     
  let c = ScanColor()
  if c = "ERR" then
    CalibrateSensorPosition()
    scanWhileErr()
  else c
Run Code Online (Sandbox Code Playgroud)

然后从主块调用此函数:

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()
Run Code Online (Sandbox Code Playgroud)

除此之外,我也改变了你match对布尔成一个普通的if-当你只有两个案件,他们是布尔值,真的是有在不使用点match以上if.

另外,我保留了你的可变变量c,但我怀疑你不再需要它,这要归功于递归.


Gus*_*Gus 6

在F#中不存在中断,我个人会尝试避免在C#中断,因为有许多替代/更清晰的方法来打破循环.

保持命令式代码风格的简单修复将是这样的:

c <- ScanColor()
while (c = "ERR") do
    CalibrateSensorPosition()
    c <- ScanColor()
ResetSensorPosition()
Run Code Online (Sandbox Code Playgroud)

但是在F#中可以进一步压缩这个单线程:

while (c <- ScanColor(); c = "ERR") do CalibrateSensorPosition()
Run Code Online (Sandbox Code Playgroud)