F# break from while loop

2019-04-18 23:53发布

There is any way to do it like C/C#?

For example (C# style)

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

7条回答
小情绪 Triste *
2楼-- · 2019-04-19 00:03

For these kind of problems you could use a recursive function.

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
查看更多
手持菜刀,她持情操
3楼-- · 2019-04-19 00:08

This is really ugly, but in my case it worked.

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

    if breakCondition then
        Break <- true
done

This is useful for do-while loops, because it guarantees that the loop is executed at least once.

I hope there's a more elegant solution. I don't like the recursive one, because I'm afraid of stack overflows. :-(

查看更多
虎瘦雄心在
4楼-- · 2019-04-19 00:11

Recently I tried to solve a similar situation:

A list of, say, 10 pieces of data. Each of them must be queried against a Restful server, then get a result for each.

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

The problem:

  • If there is a failed API call (e.g. network issue), there is no point making further calls as we need all the 10 results available. The entire process should stop ASAP when an API call fails.

The naive approach: use 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
)

But as said, it's not optimal. When a failed API occurs, the remaining items keep being processed. They do something that is ignored at the end anyway.

The hacky approach: use List.tryFindIndex()

Unlike map(), we must store the results somewhere in the lamda function. A reasonable choice is to use mutable list. So when tryFindIndex() returns None, we know that everything was ok and can start making use of the mutable list.

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..."

The idiomatic approach: use recursion

Not very idiomatic as it uses Exception to stop the operation.

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"

The old-fashion imperative approach: while... do

This still involves mutable list.

查看更多
手持菜刀,她持情操
5楼-- · 2019-04-19 00:12

Try this:

exception BreakException

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

I know that some folks don't like to use exceptions. But it has merits.

  • You don't have to think about complicated recursive function. Of cause you can do that, but sometimes it is unnecessarily bothersome and using exception is simpler.

  • This method allows you to break at halfway of the loop body. (Break "flag" method is simple too but it only allows to break at the end of the loop body.)

  • You can easily escape from nested loop.

查看更多
地球回转人心会变
6楼-- · 2019-04-19 00:12
seq { 
    for i = 0 to 99 do
        if i = 66 then yield ()
}
|> Seq.tryItem 0
|> ignore
查看更多
叼着烟拽天下
7楼-- · 2019-04-19 00:16

You have to change it to a while loop.

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

(This breaks when i gets to 66--but yes the syntax is quite different, another variable is introduced, etc.)

查看更多
登录 后发表回答