如何将 F# 结果类型列表拆分为内部类型列表

How to split F# result type list into lists of inner type

我有一个list/sequence如下Result<DataEntry, exn> []。此列表是通过根据一些用户输入并行调用多个 API 端点来填充的。

我不在乎某些调用是否失败,只要至少有 1 个调用成功即可。然后我需要对成功列表执行多个操作。

我的问题是如何将结果列表划分为 exn []DataEntry [] 列表。我尝试了以下方法:

// allData is Result<DataEntry, exn> []

let filterOutErrors (input: Result<DataEntry, exn>) =
    match input with
    | Ok v -> true
    | _ -> false

let values, err = allData |> Array.partition filterOutErrors

这原则上满足要求,因为 values 包含所有成功案例,但可以理解的是,编译器无法推断类型,因此 valueserr 都包含 Result<DataEntry, exn>.

是否有任何方法可以拆分结果列表 Result<Success, Err>,以便最终得到内部类型的单独列表?

你可以像这样提取好的和坏的。

let values =
    allData
    |> Array.choose (fun r ->
        match r with
        | Result.Ok ok -> Some ok
        | Result.Error _ -> None)

let err =
    allData
    |> Array.choose (fun r ->
        match r with
        | Result.Ok _ -> None
        | Result.Error error -> Some error)

您似乎对使用数组还是列表感到困惑。尽管您多次提到列表,但您在片段和问题文本中使用的 F# 代码都指向数组的使用。

最近有人建议我们在类型中使用 array 而不是 [] 符号,因为 F# 使用符号 [] 表示 [=有些地方是 14=],有些地方是 array。还有用于数组的符号 [||],这可能会增加更多的混乱。

因此在这种情况下建议 Result<DataEntry,exn> array

Is there any way to split a list of result Result<Success, Err> such that you end up with separate lists of the inner type?

记住Seq/List/Array是可折叠的,所以你可以用fold转换成Seq/List / Array'T 转换为任何其他类型 'S。在这里你想从 []Result<DataEntry, exn> 转到例如元组 list<DataEntry> * list<exn>。我们可以定义以下文件夹函数,它采用 list<'a> * list<'b> 类型的初始状态 s 和结果 Result<'a, 'b> 和 returns 你的列表元组 list<'a> * list<'b>:

let listFolder s r =  
    match r with
    | Ok data -> (data :: (fst s), snd s)
    | Error err -> (fst s, err :: (snd s))

然后您可以按如下方式折叠数组:

let (values, err) =  Seq.fold listFolder ([], []) allData