f# - 在 f# 中使用 Result 提取结果或聚合错误的简洁方法
问题描述
我有一个从网格收集数据的系统。它按行组织。处理的每一行都返回一个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 元素并使用该列表返回结果
解决方案
您在这里要做的是折叠,这是一种迭代列表的所有元素同时保持某种状态的方法。在这种情况下,状态将是最终结果值 -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 [])
推荐阅读
- git - 我可以使用 Git 以两种方式更改提交历史记录吗?
- amazon-web-services - AWS 多 DNS A 记录创建
- sql-server - SQL Server XML 命名空间冒号
- android - 如何使用 Volley 在 GET 请求中发送正文
- grpc - 在 K6 中,我们可以在不指定端口号的情况下连接到 GRPC 服务吗?
- java - 如何从数据库中获取 300 万条记录并生成 CSV 文件
- docker - Dockerfile dotnet/sdk/5.0 错误 - container_linux.go:380:启动容器进程导致:exec:“cmd”:$PATH 中找不到可执行文件
- javascript - 从 d3.js 中的 json API 绘制地图?
- javascript - DOMContentLoaded 将在我的页面上触发两次
- javascript - 无法暂停动画 SVG