F# break from while loop

后端 未结 7 2097
甜味超标
甜味超标 2021-02-18 14:30

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条回答
  •  悲&欢浪女
    2021-02-18 15:15

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

提交回复
热议问题