我有一个从网格收集数据的系统。它按行组织。
处理的每一行都会返回 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/