如何在 F# 中将此 CE 修改为 return 作为单个项目与列表的错误?
How to modify this CE to return Error as a single item vs. a list, in F#?
我又问了一个关于如何制作应用async/result表达式的问题。
用户@Brian_Berns 给出了一个很好的答案:
唯一需要注意的是,Result 的错误部分需要在一个数组中,这对于新代码来说效果很好,但不能很好地与现有函数一起使用。
布莱恩的回答是:
type Validation<'a, 'err> = Result<'a, List<'err>>
type AsyncValidation<'a, 'err> = Async<Validation<'a, 'err>>
module AsyncValidation =
let bind (f : _ -> AsyncValidation<_, _>) (av : AsyncValidation<_, _>) : AsyncValidation<_, _> =
async {
match! av with
| Ok a -> return! (f a)
| Error errs -> return Error errs
}
let ok a : AsyncValidation<_, _> =
async { return Ok a }
let zip (av1 : AsyncValidation<_, _>) (av2 : AsyncValidation<_, _>) : AsyncValidation<_, _> =
async {
let! v1 = av1
let! v2 = av2
match v1, v2 with
| Ok a1, Ok a2 -> return Ok (a1, a2)
| Error errs, Ok _
| Ok _, Error errs -> return Error errs
| Error errs1, Error errs2 -> return Error (errs1 @ errs2)
}
type AsyncValidationBuilder() =
member _.Bind(av, f) = AsyncValidation.bind f av
member _.Return(a) = AsyncValidation.ok a
member _.MergeSources(av1, av2) = AsyncValidation.zip av1 av2
let asyncValidation = AsyncValidationBuilder()
和他的工作示例:
let doSomethingAsync () = async { return Ok 1 }
let doSomethingElseAsync () = async { return Error ["hello"] }
let andAnotherThingAsync () = async { return Error ["world"] }
let test =
asyncValidation {
let! a = doSomethingAsync ()
and! b = doSomethingElseAsync ()
and! c = andAnotherThingAsync ()
return a + b + c
} |> Async.RunSynchronously
printfn "%A" test // Error ["hello"; "world"]
我没有花太多时间研究构建 CE,但我现在才开始。
我的问题是如何 return Result.Error 作为一个项目与一个包含项目的列表。在示例中,这意味着更改:
let doSomethingElseAsync () = async { return Error ["hello"] }
let andAnotherThingAsync () = async { return Error ["world"] }
到
let doSomethingElseAsync () = async { return Error "hello" }
let andAnotherThingAsync () = async { return Error "world" }
更新答案
为了完成这项工作,我们需要构建器中的 Source
成员来为我们进行转换:
type AsyncValidationBuilder() =
member _.Bind(av, f) = AsyncValidation.bind f av
member _.Return(a) = AsyncValidation.ok a
member _.MergeSources(av1, av2) = AsyncValidation.zip av1 av2
member _.Source(asyncResult) : AsyncValidation<_, _> =
async {
let! result = asyncResult
return Result.mapError List.singleton result
}
测试代码如下所示:
let doSomethingAsync () = async { return Ok 1 }
let doSomethingElseAsync () = async { return Error "hello" }
let andAnotherThingAsync () = async { return Error "world" }
let test =
asyncValidation {
let! a = doSomethingAsync ()
and! b = doSomethingElseAsync ()
and! c = andAnotherThingAsync ()
return a + b + c
} |> Async.RunSynchronously
printfn "%A" test
我又问了一个关于如何制作应用async/result表达式的问题。
用户@Brian_Berns 给出了一个很好的答案:
唯一需要注意的是,Result 的错误部分需要在一个数组中,这对于新代码来说效果很好,但不能很好地与现有函数一起使用。
布莱恩的回答是:
type Validation<'a, 'err> = Result<'a, List<'err>>
type AsyncValidation<'a, 'err> = Async<Validation<'a, 'err>>
module AsyncValidation =
let bind (f : _ -> AsyncValidation<_, _>) (av : AsyncValidation<_, _>) : AsyncValidation<_, _> =
async {
match! av with
| Ok a -> return! (f a)
| Error errs -> return Error errs
}
let ok a : AsyncValidation<_, _> =
async { return Ok a }
let zip (av1 : AsyncValidation<_, _>) (av2 : AsyncValidation<_, _>) : AsyncValidation<_, _> =
async {
let! v1 = av1
let! v2 = av2
match v1, v2 with
| Ok a1, Ok a2 -> return Ok (a1, a2)
| Error errs, Ok _
| Ok _, Error errs -> return Error errs
| Error errs1, Error errs2 -> return Error (errs1 @ errs2)
}
type AsyncValidationBuilder() =
member _.Bind(av, f) = AsyncValidation.bind f av
member _.Return(a) = AsyncValidation.ok a
member _.MergeSources(av1, av2) = AsyncValidation.zip av1 av2
let asyncValidation = AsyncValidationBuilder()
和他的工作示例:
let doSomethingAsync () = async { return Ok 1 }
let doSomethingElseAsync () = async { return Error ["hello"] }
let andAnotherThingAsync () = async { return Error ["world"] }
let test =
asyncValidation {
let! a = doSomethingAsync ()
and! b = doSomethingElseAsync ()
and! c = andAnotherThingAsync ()
return a + b + c
} |> Async.RunSynchronously
printfn "%A" test // Error ["hello"; "world"]
我没有花太多时间研究构建 CE,但我现在才开始。
我的问题是如何 return Result.Error 作为一个项目与一个包含项目的列表。在示例中,这意味着更改:
let doSomethingElseAsync () = async { return Error ["hello"] }
let andAnotherThingAsync () = async { return Error ["world"] }
到
let doSomethingElseAsync () = async { return Error "hello" }
let andAnotherThingAsync () = async { return Error "world" }
更新答案
为了完成这项工作,我们需要构建器中的 Source
成员来为我们进行转换:
type AsyncValidationBuilder() =
member _.Bind(av, f) = AsyncValidation.bind f av
member _.Return(a) = AsyncValidation.ok a
member _.MergeSources(av1, av2) = AsyncValidation.zip av1 av2
member _.Source(asyncResult) : AsyncValidation<_, _> =
async {
let! result = asyncResult
return Result.mapError List.singleton result
}
测试代码如下所示:
let doSomethingAsync () = async { return Ok 1 }
let doSomethingElseAsync () = async { return Error "hello" }
let andAnotherThingAsync () = async { return Error "world" }
let test =
asyncValidation {
let! a = doSomethingAsync ()
and! b = doSomethingElseAsync ()
and! c = andAnotherThingAsync ()
return a + b + c
} |> Async.RunSynchronously
printfn "%A" test