异步不可知的高阶函数
Async agnostic higher order functions
假设我们有一个提供高阶函数的库applyTest
。
这能否与异步函数一起使用asyncFunction
,同时保留异步代码的优点?
是否可以将库设计为更好地支持异步应用程序而不专门提供异步版本?
let applyTest f =
f 2 > 0
let syncFunction x =
x - 1
let asyncFunction x =
x - 2 |> async.Return
async {
let a = applyTest syncFunction
let b = applyTest (asyncFunction >> Async.RunSynchronously)
printfn "a = %b, b = %b" a b
}
|> Async.RunSynchronously
如果您不想丢失强类型检查或 运行 同步异步计算(如您的示例),则需要提供单独的异步版本。这两件事都应该尽量避免。
如果您想避免重复实际测试部分 (f 2 > 0
),您可以将其拆分为一个将参数 2
传递给函数的函数和一个检查值的函数大于零:
// LIBRARY CODE
let checkValue x = x > 0
// This function is generic so it can return a value or an async value
// (int -> 'a) -> 'a
let runTestFunction f = f 2
// (int -> int) -> bool
let applyTest f = f |> runTestFunction |> checkValue
// (int -> Async<int>) -> Async<bool>
let applyTestAsync f = async {
let! value = runTestFunction f // use let! to await the value
return checkValue value }
// USAGE
let syncFunction x = x - 1
let asyncFunction x = x - 2 |> async.Return
async {
let a = applyTest syncFunction
let! b = applyTestAsync asyncFunction // use let! to await the test result
printfn "a = %b, b = %b" a b
}
另一种选择是使用重载方法。这建立在上面定义的函数之上:
type Test =
static member Apply f = applyTest f
static member Apply f = applyTestAsync f
// USAGE
async {
let a = Test.Apply syncFunction
let! b = Test.Apply asyncFunction // We still need to consume this differently with a let!
printfn "a = %b, b = %b" a b
}
假设我们有一个提供高阶函数的库applyTest
。
这能否与异步函数一起使用asyncFunction
,同时保留异步代码的优点?
是否可以将库设计为更好地支持异步应用程序而不专门提供异步版本?
let applyTest f =
f 2 > 0
let syncFunction x =
x - 1
let asyncFunction x =
x - 2 |> async.Return
async {
let a = applyTest syncFunction
let b = applyTest (asyncFunction >> Async.RunSynchronously)
printfn "a = %b, b = %b" a b
}
|> Async.RunSynchronously
如果您不想丢失强类型检查或 运行 同步异步计算(如您的示例),则需要提供单独的异步版本。这两件事都应该尽量避免。
如果您想避免重复实际测试部分 (f 2 > 0
),您可以将其拆分为一个将参数 2
传递给函数的函数和一个检查值的函数大于零:
// LIBRARY CODE
let checkValue x = x > 0
// This function is generic so it can return a value or an async value
// (int -> 'a) -> 'a
let runTestFunction f = f 2
// (int -> int) -> bool
let applyTest f = f |> runTestFunction |> checkValue
// (int -> Async<int>) -> Async<bool>
let applyTestAsync f = async {
let! value = runTestFunction f // use let! to await the value
return checkValue value }
// USAGE
let syncFunction x = x - 1
let asyncFunction x = x - 2 |> async.Return
async {
let a = applyTest syncFunction
let! b = applyTestAsync asyncFunction // use let! to await the test result
printfn "a = %b, b = %b" a b
}
另一种选择是使用重载方法。这建立在上面定义的函数之上:
type Test =
static member Apply f = applyTest f
static member Apply f = applyTestAsync f
// USAGE
async {
let a = Test.Apply syncFunction
let! b = Test.Apply asyncFunction // We still need to consume this differently with a let!
printfn "a = %b, b = %b" a b
}