【问题标题】:Async agnostic higher order functions与异步无关的高阶函数
【发布时间】:2019-08-05 06:17:36
【问题描述】:

假设我们有一个提供高阶函数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

【问题讨论】:

    标签: asynchronous f# higher-order-functions


    【解决方案1】:

    如果您不想丢失强类型检查或像示例中那样同步运行异步计算,则需要提供单独的异步版本。这两件事都应该尽量避免。

    如果您想避免重复实际测试部分 (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
    }
    

    【讨论】:

    • 谢谢,我会为我的架构尝试不同的方法。我发现了许多探索这个领域的有趣博客,从IO in Haskell 的一个等效问题开始。虽然有些业务逻辑会溢出到外层,但实际上它可能会简化我的整体设计。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 2020-10-01
    • 2016-05-07
    相关资源
    最近更新 更多