Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 在计算表达式中将结果列表转换为列表结果?_F#_Computation Expression - Fatal编程技术网

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
还有一个variant
List.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"