将结果列表转换为计算表达式中列表的结果?

sdg*_*sdh 5 f# computation-expression

我有一个Result<'T, 'E> list我想Result<'T list, 'E>按照这些规则变成单一的:

  • 如果有Result,Error那么结果应该是Error
  • 如果结果是,Error它应该是Error列表中的第一个
  • 如果每个结果都是a,OK则结果应为a,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
Run Code Online (Sandbox Code Playgroud)

但是,这似乎已经在标准库中实现了.有吗?

其次,我有一个Result像这样的计算表达式:

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()
Run Code Online (Sandbox Code Playgroud)

我可以all在内部使用,result { ... }但可能进一步整合吗?例如通过实施ResultBuilder.For?

sdg*_*sdh 8

此功能由包提供FsToolkit.ErrorHandling。该函数List.sequenceResultM将返回:

  • A包含所有值Result.Ok的列表Ok
  • 或者,aResult.Error仅包含第一个Error值

还有一个变体List.sequenceResultA,它返回找到的所有错误的列表。

#r "nuget: FsToolkit.ErrorHandling, 2.0.0"

open FsToolkit.ErrorHandling

let xs : Result<int, string> list =
  [
    Ok 123
    Ok 456
  ]

let xa = List.sequenceResultA xs // Ok [123; 456]
let xm = List.sequenceResultM xs // Ok [123; 456]

printfn "xa: %A" xa
printfn "xm: %A" xm

let ys =
  [
    Ok 123
    Ok 456
    Error "abc"
    Ok 789
  ]

let ya = List.sequenceResultA ys // Error ["abc"]
let ym = List.sequenceResultM ys // Error "abc"

printfn "ya: %A" ya
printfn "ym: %A" ym

let zs =
  [
    Ok 123
    Error "abc"
    Error "def"
    Ok 456
  ]

let za = List.sequenceResultA zs // Error ["abc"; "def"]
let zm = List.sequenceResultM zs // Error "abc"

printfn "za: %A" za
printfn "zm: %A" zm
Run Code Online (Sandbox Code Playgroud)
xa: Ok [123; 456]
xm: Ok [123; 456]
ya: Error ["abc"]
ym: Error "abc"
za: Error ["abc"; "def"]
zm: Error "abc"
Run Code Online (Sandbox Code Playgroud)

就计算表达式(也由 提供FsToolkit.ErrorHandling)而言,您可以这样做:

xa: Ok [123; 456]
xm: Ok [123; 456]
ya: Error ["abc"]
ym: Error "abc"
za: Error ["abc"; "def"]
zm: Error "abc"
Run Code Online (Sandbox Code Playgroud)


rmu*_*unn 7

你有一个Result<'a, 'e> list想要的Result<'a list, 'e>.这听起来像https://fsharpforfunandprofit.com/posts/elevated-world-4/中sequence描述的功能(它与s 无关,尽管名称听起来像).快速检查https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/result.fs表明此功能尚未在标准FSharp.Core库中实现,因此您我需要自己实现它.seq

顺便说一句,如果你还没有读过Scott Wlaschin的"高架世界"系列,我不建议从中间开始我链接的文章.从本文开始,因为它构建了理解"遍历"和"序列"函数所需的背景知识.然后你就会知道实现其中一个函数的一般模式.

至于你的第二个问题,你能提供一些更具体的细节吗?例如,您想要出于什么行为ResultBuilder.For?for表达式所期望的正常行为是获取Result<'a, 'e> list(或seq或数组)并为Result<'a, 'e>列表或seq或数组中的每个内部块运行一次内部块.如果你试图在all这里使用你的函数,你会遇到类型不匹配Result<'a, 'e>(这是F#期望CE的.For方法产生的)以及Result<'a list, 'e>你的all方法返回的类型.具体到底你想用你的ResultBuilder.For方法做什么?