F# 在计算表达式中将结果列表转换为列表结果?
我有一个F# 在计算表达式中将结果列表转换为列表结果?,f#,computation-expression,F#,Computation Expression,我有一个结果列表,我想按照以下规则将其转换为单个结果: 如果任何结果为错误,则结果应为错误 如果结果为错误,则应为列表中的第一个错误 如果每个结果都是OK,那么结果应该是OK,并且应该保持列表顺序 因此,我尝试了一下,并按如下方式实施: let all xs = let folder = fun state next -> match (state, next) with | (Result.Ok ys, Result.Ok y) -> ys |>
结果列表
,我想按照以下规则将其转换为单个结果
:
- 如果任何
为结果
,则结果应为错误
错误
- 如果结果为
,则应为列表中的第一个错误
错误
- 如果每个结果都是
,那么结果应该是OK
,并且应该保持列表顺序OK
let all xs =
let folder = fun state next ->
match (state, next) with
| (Result.Ok ys, Result.Ok y) -> ys |> List.append [ y ] |> Result.Ok
| (Result.Error e, _) -> Result.Error e
| (_, Result.Error e) -> Result.Error e
Seq.fold folder (Result.Ok []) xs
然而,这似乎已经在标准库中实现了。是吗
其次,我有一个结果的计算表达式,如下所示:
type ResultBuilder () =
member this.Bind(x, f) =
match x with
| Result.Ok o -> f o
| Result.Error e -> Result.Error e
member this.Return(value) = Result.Ok value
member this.ReturnFrom(value) = value
let result = new ResultBuilder()
我可以在结果{…}
中使用all
,但是否可以进一步集成?例如,通过实现ResultBuilder.For
?您有一个结果列表
,并且想要一个结果
。这听起来像中描述的sequence
函数(不管名称如何,它与seq
s无关)。对的快速检查表明此函数尚未在标准FSharp.Core库中实现,因此您需要自己实现它
关于你的第二个问题,你能提供更多的细节吗?例如,您希望ResultBuilder.For
有什么行为?表达式的正常预期行为是获取一个结果列表(或seq或数组),并为列表或seq或数组中的每个结果运行一次内部块。如果您试图在此处使用all
函数,则Result
与all
方法返回的Result
之间的类型不匹配(这是F#期望CE的方法生成的)。您希望您的ResultBuilder.For
方法具体做什么?下面是我的解决方案,它接受一系列结果(而不是列表),因此验证是惰性的
let takeTo<'T> predicate (source: 'T seq) =
seq {
use en = source.GetEnumerator()
let mutable isDone = false
while isDone = false && en.MoveNext() do
yield en.Current
isDone <- predicate en.Current
}
let fromResults rs =
rs
|> Seq.scan (fun (vs, err) i ->
match i with
| Ok v -> (v::vs,err)
| Error e -> (vs, Some e)) ([], None)
|> Seq.takeTo (fun (vs, err) -> err.IsSome)
|> Seq.last
|> fun (vs, err) ->
match err with
| None -> vs |> List.rev |> Ok
| Some err -> Error err
让takeTo
匹配
|Ok v->(v::vs,err)
|错误e->(vs,某些e))([],无)
|>Seq.takeTo(乐趣(vs,err)->err.IsSome)
|>倒数第二
|>乐趣(vs,err)->
错配
|无->vs |>List.rev |>确定
|一些错误->错误错误错误
此功能由软件包提供。函数List.sequenceResultTM
将返回以下任一结果:
- 一个
结果。Ok
包含所有Ok
值的列表
- 或者,一个
结果.Error
只包含第一个Error
值
还有一个variantList.sequenceResultA
,它返回找到的所有错误的列表
#r“nuget:FsToolkit.ErrorHandling,2.0.0”
打开FsToolkit.ErrorHandling
让xs:结果列表=
[
好的,123
好的456
]
设xa=List.sequenceResultA xs
设xm=List.sequenceResultM xs
printfn“xa:%A”xa
printfn“xm:%A”xm
让我们来看看=
[
好的,123
好的456
错误“abc”
好的,789
]
设ya=List.sequenceResultA ys
设ym=List.sequenceResultM ys
printfn“ya:%A”ya
printfn“ym:%A”ym
让zs=
[
好的,123
错误“abc”
错误“def”
好的456
]
设za=List.sequenceResultA zs
设zm=List.sequenceResultM zs
printfn“za:%A”za
printfn“zm:%A”zm
在计算表达式方面(也由FsToolkit.ErrorHandling
提供),您可以执行以下操作:
#r“nuget:FsToolkit.ErrorHandling,2.0.0”
打开FsToolkit.ErrorHandling
让我们打印所有的X=
结果{
让!xs=List.sequenceResultA xs
对于x-in-xs-do
printfn“%A”x
}
它不在FSharpCore中,但一些扩展库实现了该函数,例如,它被称为sequence
,可用于任何应用程序。
xa: Ok [123; 456]
xm: Ok [123; 456]
ya: Error ["abc"]
ym: Error "abc"
za: Error ["abc"; "def"]
zm: Error "abc"