Есть ли способ сделать это как C/C#
?
Например (стиль С#)
for( int i=0; i<100; i++)
{
if(i==66)
break;
}
Есть ли способ сделать это как C/C#
?
Например (стиль С#)
for( int i=0; i<100; i++)
{
if(i==66)
break;
}
Короткий ответ - нет. Обычно вы используете функцию более высокого порядка, чтобы выразить ту же функциональность. Существует ряд функций, которые позволяют делать это, соответствующие различным шаблонам (поэтому, если вы описываете, что именно вам нужно, кто-то может дать вам лучший ответ).
Например, функция 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
. Вот пример, но, как я уже сказал, это не так эффективно.
Вы должны изменить его на цикл while.
let (i, ans) = (ref 0, ref -1)
while(!i < 100 and !ans < 0) do
if !i = 66 then
ans := !i
ans
(Это прерывается, когда я добираюсь до 66, но да, синтаксис совсем другой, другая переменная введена и т.д.)
Это действительно уродливо, но в моем случае это сработало.
let mutable Break = false
while not Break do
//doStuff
if breakCondition then
Break <- true
done
Это полезно для циклов do-while, поскольку гарантирует, что цикл выполняется хотя бы один раз.
Надеюсь, там будет более элегантное решение. Мне не нравится рекурсивный, потому что я боюсь.: - (
Попробуйте следующее:
exception BreakException
try
for i = 0 to 99 do
if i = 66 then
raise BreakException
with BreakException -> ()
Я знаю, что некоторые люди не любят использовать исключения. Но это имеет свои достоинства.
Вам не нужно думать о сложной рекурсивной функции. из потому что вы можете это сделать, но иногда это излишне надоедливо и использование исключения проще.
Этот метод позволяет вам разбить половину тела цикла. (Флажок "флаг" также прост, но он позволяет только разбивать в конце тела цикла.)
Вы можете легко выйти из вложенного цикла.
seq {
for i = 0 to 99 do
if i = 66 then yield ()
}
|> Seq.tryItem 0
|> ignore
Для таких проблем вы можете использовать рекурсивную функцию.
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
Недавно я попытался решить аналогичную ситуацию:
Список, скажем, 10 штук данных. Каждый из них должен быть запрошен на сервере Restful, а затем получить результат для каждого.
let lst = [4;6;1;8]
Эта проблема:
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
списком.