f# - 在 f# 中提取结果或使用 Result 聚合错误的简洁方法

标签 f#

我有一个从网格收集数据的系统。它按行组织。 处理的每一行都会返回 Result<data, string list>目的。 错误案例中的列表是解析过程中遇到的错误列表。每行可以有多个错误,但只有一个有效结果。

我想将数据聚合到一个列表 data list如果没有错误,或者制作完整的错误列表,在 string list如果至少有一个错误,请填写表单。

最终返回类型为Result<data list, string list>

我有以下代码:

let hasErrors =
    gridRows |> List.exists (fun r -> match r with | Ok _ -> false | Error _ -> true)

// build the layer list, or return the errors
match hasErrors with
| false -> Ok (
            gridRows
            |> List.map (fun r ->
                match r with
                | Ok layer -> layer
                | Error _  -> failwith "this should never execute"
            )
          )
| true -> Error (
                gridRows
                |> List.collect (fun r ->
                    match r with
                    | Ok _ -> []
                    | Error messages -> messages
                )
             )

但这感觉非常笨重且难以阅读。

使用 Result<>,有没有办法做到:

  • 如果出现任何错误,则收集列表中的所有错误元素并返回该列表的结果
  • 如果没有错误,则收集列表中所有正常元素并返回该列表的结果

最佳答案

您想要在这里做的是折叠,这是一种迭代列表中所有元素的方法,同时保持某种状态。这种情况下的状态将是最终的结果值 - 要么 Ok 包含所有值,要么 Error 包含所有错误。

折叠功能非常简单:

let f state item = 
    match state, item with
    | Ok prevResults, Ok res -> Ok (prevResults @ [res])
    | Ok _, Error errs -> Error errs
    | Error errs, Ok _ -> Error errs
    | Error prevErrs, Error errs -> Error (prevErrs @ errs)

此函数查看“到目前为止累积的结果”(也称为“状态”)和当前项目,并针对四种可能性中的每一种,返回适当的新“到目前为止累积的结果”。

然后你就可以使用这个函数来折叠列表,初始状态为Ok []:

gridRows |> List.fold f (Ok [])

关于f# - 在 f# 中提取结果或使用 Result 聚合错误的简洁方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62958460/

相关文章:

在 .NET Core 和 Visual Studio Code 中调试用 F# 编写的 xunit 测试?

f# - 如何在 F# 中使用命名参数

c# - 通过 F# 绑定(bind)到 View 模型的接口(interface)实现期间出现 BindingError

types - 如何在 F# 中定义两个相互依赖的类型?

F#:SRTP静态扩展方法类型匹配不一致

f# - 矩阵的内存不足异常

recursion - 创建递归可区分联合值

parsing - F# ref-mutable vars 与对象字段

f# - 将大序列作为函数参数传递

c# - 错误 : a type annotation may be needed