F#从while循环中断

时间:2013-05-14 12:45:57

标签: f# while-loop break

有没有办法像C/C#那样做?

例如(C#style)

for( int i=0; i<100; i++)
{
   if(i==66)
    break;
} 

7 个答案:

答案 0 :(得分:26)

简短的回答是否定的。您通常会使用某些高阶函数来表达相同的功能。有许多功能可以让你这样做,对应不同的模式(所以如果你描述你需要什么,有人可能会给你一个更好的答案)。

例如,tryFind函数返回给定谓词返回true的序列中的第一个值,这样可以编写如下内容:

seq { 0 .. 100 } |> Seq.tryFind (fun i ->
  printfn "%d" i
  i=66)

实际上,如果你表达一些高级逻辑并且有相应的功能,这是最好的方法。如果你真的需要表达像break这样的东西,你可以使用递归函数:

let rec loop n = 
  if n < 66 then 
    printfn "%d" n
    loop (n + 1)

loop 0      

一个更具异国情调的选项(效率不高,但对DSL来说可能不错)是你可以定义一个允许你编写breakcontinue的计算表达式。 Here is an example,但正如我所说,这不是那么有效。

答案 1 :(得分:5)

这真的很难看,但就我而言,它很有用。

let mutable Break = false
while not Break do
    //doStuff

    if breakCondition then
        Break <- true
done

这对do-while循环很有用,因为它保证循环至少执行一次。

我希望有一个更优雅的解决方案。我不喜欢递归的,因为我害怕堆栈溢出。 : - (

答案 2 :(得分:4)

您必须将其更改为while循环。

let (i, ans) = (ref 0, ref -1)
while(!i < 100 and !ans < 0) do
 if !i = 66 then
   ans := !i
ans

(当我达到66时,这会中断 - 但是语法是完全不同的,引入了另一个变量,等等。)

答案 3 :(得分:1)

试试这个:

exception BreakException

try
    for i = 0 to 99 do
      if i = 66 then
        raise BreakException
with BreakException -> ()

我知道有些人不喜欢使用例外。但它有优点。

  • 您不必考虑复杂的递归函数。的 因为你可以做到这一点,但有时它是不必要的麻烦 使用异常更简单。

  • 此方法允许您在循环体的中途中断。 (Break&#34; flag&#34;方法也很简单,但它只允许在循环体的末尾断开。)

  • 您可以轻松地从嵌套循环中逃脱。

答案 4 :(得分:0)

seq { 
    for i = 0 to 99 do
        if i = 66 then yield ()
}
|> Seq.tryItem 0
|> ignore

答案 5 :(得分:0)

对于这些问题,您可以使用递归函数。

let rec IfEqualsNumber start finish num =
    if start = finish then false
    elif 
      start = num then true
    else
      let start2 = start + 1
      IfEqualsNumber start2 finish num

答案 6 :(得分:0)

最近我试图解决类似的情况:

例如10条数据的列表。必须针对Restful服务器查询其中的每个服务器,然后为每个服务器获取结果。

let lst = [4;6;1;8]

问题:

  • 如果API调用失败(例如网络问题),则没有必要再进行进一步调用,因为我们需要所有10个可用结果。当API调用失败时,整个过程应尽快停止。

天真的方法:使用List.map()

lst |> List.map (fun x -> 
    try
        use sqlComd = ...
        sqlComd.Parameters.Add("@Id", SqlDbType.BigInt).Value <- x
        sqlComd.ExecuteScala() |> Some
    with
        | :? System.Data.SqlClient.SqlException as ex -> None
)

但是如上所述,这不是最佳的。当API发生故障时,其余项目将继续得到处理。他们仍然会做一些最终被忽略的事情。

hacky方法:使用List.tryFindIndex()

map()不同,我们必须将结果存储在lamda函数中的某个位置。合理的选择是使用mutable列表。因此,当tryFindIndex()返回None时,我们知道一切正常,并且可以开始使用mutable列表了。

val myList: List<string>
let res = lst |> List.tryFindIndex (fun x ->
    try
        use sqlComd = ...
        sqlComd.Parameters.Add("@Id", SqlDbType.BigInt).Value <- x
        myList.Add(sqlComd.ExecuteScala())
        false
    with
        |:? System.Data.SqlClient.SqlException as ex -> true
)

match res with
| Some _ -> printfn "Something went wrong"
| None -> printfn "Here is the 10 results..."

惯用方法:使用递归

不太习惯,因为它使用Exception来停止操作。

exception MyException of string
let makeCall lstLocal =
    match lstLocal with
    | [] -> []
    | head::tail ->
        try
            use sqlComd = ...
            sqlComd.Parameters.Add("@Id", SqlDbType.BigInt).Value <- x
            let temp = sqlComd.ExecuteScala()
            temp :: makeCall (tail)
        with
            |:? System.Data.SqlClient.SqlException as ex -> raise MyException ex.Message

try
    let res = makeCall lst
    printfn "Here is the 10 results..."
with
    | :? MyException -> printfn "Something went wrong"

老式命令法:while... do

这仍然涉及mutable列表。

相关问题