#f#
Вопрос:
У меня есть такой раздел:
let data =
seq {
for i in source do
do some stuff...
yield result
}
Но я хотел бы превратить его в объект результата, и во время итерации у меня возникают некоторые условия, которые означают ошибку. Например:
let data =
seq {
for i in source do
do some stuff...
if a > b then .. let's abort everything and return error
yield result
} |> Ok
Расчеты довольно дороги, поэтому он предпочел бы не обертывать доходность опционом / результатом и разобраться с этим позже, если я смогу прерваться раньше.
Или, если я сделаю это, как я могу повторять, пока он не завершится или не вернет ошибку?
Как это можно сделать?
Ответ №1:
Вы можете подключиться Seq.takeWhile
и разобраться там Seq
, следует ли прерывать:
let data =
source
|> Seq.map (fun s -> ... do some stuff ...)
|> Seq.takeWhile (fun r -> ... return false if error ...)
Seq<T>
это IEnumerable<T>
так лениво, вычисления выполняются, когда из него извлекаются новые элементы.
Редактировать:
Чтобы узнать, была ли ошибка или мы достигли конца раздела, я бы пересек его, используя сгиб, чтобы раздел «исходные» элементы вычислялся на лету, и если есть ошибка, затем пройдите через остальные, не выполняя вычисления. Вот пример:
let source = seq {
1
2
3
4 }
let expensiveCalc item =
printfn "expensiveCalc called with %i" item
if item > 2 then Error (sprintf "%i is too high" item)
else Ok item
let traverse valuesResult newSourceItem =
valuesResult
|> Result.bind (fun values ->
expensiveCalc newSourceItem
|> Result.map (fun newResult -> newResult::values))
let endResult =
source
|> Seq.fold traverse (Ok [])
match endResult with
| Ok values -> printfn "%A" values
| Error error -> printfn "%s" error
Как вы можете видеть, любое число, большее 2, считается ошибкой, и при запуске оно перестает звонить expensiveCalc
после первой ошибки.
Комментарии:
1. если мои результаты вернут результат, я могу использовать время ожидания, чтобы продолжать извлекать данные до тех пор, пока не будет достигнута ошибка, но как бы я отличил конец последовательности от достигнутой ошибки?
2. @Thomas Я бы тогда свернул исходный код и рассчитал на лету. Недостатком этого, я думаю, является то, что весь исходный код истощен. См.раздел правка.
3. значит, в итоге вы делаете все расчеты? например, завернуть все в опцию и проверить, нет ли ее в конце, и если она не найдена, запустите, выберите, чтобы получить данные
4. @Thomas Нет, вычисления выполняются только до тех пор, пока не произойдет первая ошибка, но весь исходный код (до вычислений) сливается. Запустите второй пример кода выше, и вы увидите, что «expensiveCalc вызывается с %i» печатается только для чисел 1, 2 и 3 (3-ошибка), 4 никогда не вычисляется.