У меня был код, который ждал, чтобы взорвать что-то скрывающееся вокруг.Использование F # 4.1 Result
похоже на это:
module Result =
let unwindSeq (sourceSeq: #seq<Result<_, _>>) =
sourceSeq
|> Seq.fold (fun state res ->
match state with
| Error e -> Error e
| Ok innerResult ->
match res with
| Ok suc ->
Seq.singleton suc
|> Seq.append innerResult
|> Ok
| Error e -> Error e) (Ok Seq.empty)
Очевидным узким местом здесь является Seq.singleton
, добавленное к Seq.append
.Я понимаю, что это медленно (и плохо написано), но почему оно должно взорвать стек? Я не думаю, что Seq.append
по своей природе рекурсивен ...
// blows up stack, StackOverflowException
Seq.init 1000000 Result.Ok
|> Result.unwindSeq
|> printfn "%A"
И, кроме того, чтобы развернуть последовательность Result
, я исправил эту функцию, используя простой try-catch-reraise
, но это также кажется подпарам.Любые идеи о том, как сделать это более идиоматически, без принудительной оценки последовательности или взрыва стека?
Не очень идеальное раскручивание (это также приводит к типу результат-сбой), но по крайней мере без предварительного-оценка последовательности:
let unwindSeqWith throwArgument (sourceSeq: #seq<Result<_, 'a -> 'b>>) =
try
sourceSeq
|> Seq.map (throwOrReturnWith throwArgument)
|> Ok
with
| e ->
(fun _ -> raise e)
|> Error