F # перерыв из цикла while - программирование
Подтвердить что ты не робот

F # перерыв из цикла while

Есть ли способ сделать это как C/C#?

Например (стиль С#)

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

Ответ 1

Короткий ответ - нет. Обычно вы используете функцию более высокого порядка, чтобы выразить ту же функциональность. Существует ряд функций, которые позволяют делать это, соответствующие различным шаблонам (поэтому, если вы описываете, что именно вам нужно, кто-то может дать вам лучший ответ).

Например, функция 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) заключается в том, что вы можете определить выражение вычисления, которое позволяет писать break и continue. Вот пример, но, как я уже сказал, это не так эффективно.

Ответ 2

Вы должны изменить его на цикл while.

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

(Это прерывается, когда я добираюсь до 66, но да, синтаксис совсем другой, другая переменная введена и т.д.)

Ответ 3

Это действительно уродливо, но в моем случае это сработало.

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

    if breakCondition then
        Break <- true
done

Это полезно для циклов do-while, поскольку гарантирует, что цикл выполняется хотя бы один раз.

Надеюсь, там будет более элегантное решение. Мне не нравится рекурсивный, потому что я боюсь.: - (

Ответ 4

Попробуйте следующее:

exception BreakException

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

Я знаю, что некоторые люди не любят использовать исключения. Но это имеет свои достоинства.

  • Вам не нужно думать о сложной рекурсивной функции. из потому что вы можете это сделать, но иногда это излишне надоедливо и использование исключения проще.

  • Этот метод позволяет вам разбить половину тела цикла. (Флажок "флаг" также прост, но он позволяет только разбивать в конце тела цикла.)

  • Вы можете легко выйти из вложенного цикла.

Ответ 5

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

Ответ 6

Для таких проблем вы можете использовать рекурсивную функцию.

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

Недавно я попытался решить аналогичную ситуацию:

Список, скажем, 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, остальные элементы продолжают обрабатываться. В любом случае они делают что-то, что игнорируется.

Хакерный подход: используйте 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 списком.