F# 打破复杂语句中的 while 循环
F# breaking from while loop in complex statements
我有这样一个功能:
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()
在这个函数中,在while
语句中,我不能使用break,因为如你所知,F#中不使用break
。我正在寻找 break
的替代品,我看到了这个链接:
F# break from while loop
但老实说,我不确定这个解决方案是否适合我的问题。
遗憾的是 F# 不支持 break
。有各种相当复杂的方法来处理这个问题(比如 this recent one or my computation builder),但这些方法都有缺点并使您的代码相当复杂。
处理此问题的一般方法是使用递归重写代码 - 这通常会编译为与使用 break
和 continue
在 C# 中编写的代码相同的 IL。
因此,您代码段中的 while
块可以编写为递归调用自身的函数,直到结果不是 "ERR" 然后 returns c
:
let rec scanWhileErr () =
let c = ScanColor()
if c = "ERR" then
CalibrateSensorPosition()
scanWhileErr()
else c
然后从主块调用这个函数:
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()
此外,我还将布尔值上的 match
更改为普通的 if
- 当您只有两种情况并且它们是布尔值时,使用 match
真的没有意义超过 if
.
此外,我保留了您的可变变量 c
,但我怀疑由于递归,您不再需要它。
Break 在 F# 中不存在,就我个人而言,即使在 C# 中我也会尽量避免中断,因为有许多 alternative/cleaner 方法可以中断循环。
保持命令式代码风格的简单修复方法如下:
c <- ScanColor()
while (c = "ERR") do
CalibrateSensorPosition()
c <- ScanColor()
ResetSensorPosition()
但在 F# 中,它可以进一步压缩为一行代码:
while (c <- ScanColor(); c = "ERR") do CalibrateSensorPosition()
实际上,我认为这种方法很好,并且适用于我的情况:
let mutable flag = true
while (flag = true) do
c <- ScanColor()
if (c = "ERR") then
CalibrateSensorPosition()
else
flag <- false
ResetSensorPosition()
我认为一个简单的方法是,当您需要在循环中使用 "break" 时,您只需确保循环终止即可。
这方面的一个例子是,如果我们有一个像这样的 while 循环
while i < upperlimit do
if a
then break
我有这样一个功能:
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()
在这个函数中,在while
语句中,我不能使用break,因为如你所知,F#中不使用break
。我正在寻找 break
的替代品,我看到了这个链接:
F# break from while loop
但老实说,我不确定这个解决方案是否适合我的问题。
遗憾的是 F# 不支持 break
。有各种相当复杂的方法来处理这个问题(比如 this recent one or my computation builder),但这些方法都有缺点并使您的代码相当复杂。
处理此问题的一般方法是使用递归重写代码 - 这通常会编译为与使用 break
和 continue
在 C# 中编写的代码相同的 IL。
因此,您代码段中的 while
块可以编写为递归调用自身的函数,直到结果不是 "ERR" 然后 returns c
:
let rec scanWhileErr () =
let c = ScanColor()
if c = "ERR" then
CalibrateSensorPosition()
scanWhileErr()
else c
然后从主块调用这个函数:
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()
此外,我还将布尔值上的 match
更改为普通的 if
- 当您只有两种情况并且它们是布尔值时,使用 match
真的没有意义超过 if
.
此外,我保留了您的可变变量 c
,但我怀疑由于递归,您不再需要它。
Break 在 F# 中不存在,就我个人而言,即使在 C# 中我也会尽量避免中断,因为有许多 alternative/cleaner 方法可以中断循环。
保持命令式代码风格的简单修复方法如下:
c <- ScanColor()
while (c = "ERR") do
CalibrateSensorPosition()
c <- ScanColor()
ResetSensorPosition()
但在 F# 中,它可以进一步压缩为一行代码:
while (c <- ScanColor(); c = "ERR") do CalibrateSensorPosition()
实际上,我认为这种方法很好,并且适用于我的情况:
let mutable flag = true
while (flag = true) do
c <- ScanColor()
if (c = "ERR") then
CalibrateSensorPosition()
else
flag <- false
ResetSensorPosition()
我认为一个简单的方法是,当您需要在循环中使用 "break" 时,您只需确保循环终止即可。
这方面的一个例子是,如果我们有一个像这样的 while 循环
while i < upperlimit do
if a
then break