F# 是否有异步验证库?
Is there an async validate lib for F#?
我在我的代码中经常使用 asyncResult,但它会在第一个错误时退出:
asyncResult {
let! a = allGood()
let! b = thisReturnsError()
let! c = neverExecuted()
}
但有时我想执行所有功能并总结错误:
validation {
let! a = doSomething()
and! b = doSomethingElse()
and! c = andAnotherThing()
}
然后我要么得到一个 Ok,要么得到一个带有错误列表的错误。
太棒了,但我希望两者都能做到!
asyncValidation {
let! a = doSomethingAsync()
and! b = doSomethingElseAsync()
and! c = andAnotherThingAsync()
}
有库做这个吗?
我只是把它放在一起,但我认为它有效:
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"]
对于 F#+,您可以使用 Compose
:
组合应用程序
#r @"nuget: FSharpPlus"
open FSharpPlus
open FSharpPlus.Data
// Generic applicative CE. At the moment not included in the library.
type ApplicativeBuilder<'a>() =
inherit MonadFxStrictBuilder<'a>()
member inline _.BindReturn(x, f) = map f x
let applicative<'t> = ApplicativeBuilder<'t> ()
let allGoodAsync () : Async<Validation<string, int>> = async { printfn "first success"; return Success 1 }
let thisResturnsErrorAsync () : Async<Validation<string, int>> = async { return Failure "thisReturnsError" }
let neverExecutedAsync () : Async<Validation<string, int>> = async { printfn "actually executed"; return Success 3 }
let x: Async<Validation<string, _>> =
applicative {
let! (a: int) = allGoodAsync () |> Compose
and! (b: int) = thisResturnsErrorAsync () |> Compose
and! (c: int) = neverExecutedAsync () |> Compose
return a + b + c
}
|> Compose.run
let y = Async.RunSynchronously x
结果
>
first success
actually executed
val y: Validation<string,int> = Failure "thisReturnsError"
我在我的代码中经常使用 asyncResult,但它会在第一个错误时退出:
asyncResult {
let! a = allGood()
let! b = thisReturnsError()
let! c = neverExecuted()
}
但有时我想执行所有功能并总结错误:
validation {
let! a = doSomething()
and! b = doSomethingElse()
and! c = andAnotherThing()
}
然后我要么得到一个 Ok,要么得到一个带有错误列表的错误。
太棒了,但我希望两者都能做到!
asyncValidation {
let! a = doSomethingAsync()
and! b = doSomethingElseAsync()
and! c = andAnotherThingAsync()
}
有库做这个吗?
我只是把它放在一起,但我认为它有效:
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"]
对于 F#+,您可以使用 Compose
:
#r @"nuget: FSharpPlus"
open FSharpPlus
open FSharpPlus.Data
// Generic applicative CE. At the moment not included in the library.
type ApplicativeBuilder<'a>() =
inherit MonadFxStrictBuilder<'a>()
member inline _.BindReturn(x, f) = map f x
let applicative<'t> = ApplicativeBuilder<'t> ()
let allGoodAsync () : Async<Validation<string, int>> = async { printfn "first success"; return Success 1 }
let thisResturnsErrorAsync () : Async<Validation<string, int>> = async { return Failure "thisReturnsError" }
let neverExecutedAsync () : Async<Validation<string, int>> = async { printfn "actually executed"; return Success 3 }
let x: Async<Validation<string, _>> =
applicative {
let! (a: int) = allGoodAsync () |> Compose
and! (b: int) = thisResturnsErrorAsync () |> Compose
and! (c: int) = neverExecutedAsync () |> Compose
return a + b + c
}
|> Compose.run
let y = Async.RunSynchronously x
结果
>
first success
actually executed
val y: Validation<string,int> = Failure "thisReturnsError"