F# break from while loop

流过昼夜 提交于 2019-12-13 11:52:43

问题


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;
} 

回答1:


The short answer is no. You would generally use some higher-order function to express the same functionality. There is a number of functions that let you do this, corresponding to different patterns (so if you describe what exactly you need, someone might give you a better answer).

For example, tryFind function returns the first value from a sequence for which a given predicate returns true, which lets you write something like this:

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

In practice, this is the best way to go if you are expressing some high-level logic and there is a corresponding function. If you really need to express something like break, you can use a recursive function:

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

loop 0      

A more exotic option (that is not as efficient, but may be nice for DSLs) is that you can define a computation expression that lets you write break and continue. Here is an example, but as I said, this is not as efficient.




回答2:


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. :-(




回答3:


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




回答4:


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.




回答5:


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



回答6:


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



回答7:


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.



来源:https://stackoverflow.com/questions/16543548/f-break-from-while-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!