f# - 如何在 F# 中异步下载网页并捕获错误

标签 f# f#-data

我一直在尝试找出惯用的 F# 方式来异步下载网页并处理任何错误/HTTP 失败代码,我认为这是我迄今为止最接近的尝试,但我在 Choice1Of2 行上遇到类型错误

我愿意

a) 了解失败的原因(我仍在学习 F#)
b)知道这是否是正确的方法/如何使这项工作发挥作用,或者我是否完全走错了路

FS0001    This expression was expected to have type
    'Async<Choice<string,exn>>'    
but here has type
    'Choice<'a,'b>'
    let fetchAsync url = async {
        return! Async.Catch(async {
            let! str = Http.AsyncRequestString(url)
            return str })
    }

    let result = fetchAsync "http://www.example.bad"
    match result with      
    | Choice1Of2 v -> logger.LogInformation("worked")
    | Choice2Of2 ex -> logger.LogInformation("failed")  

最佳答案

a) 为什么会失败

您的fetchAsync函数返回 Async<Choice<_>>并且你的模式匹配好像函数只返回 Choice<_> .不幸的是,您不能在 Async 上进行模式匹配,因为这将是一个阻塞操作,正是 Async 尝试远离的。

b) 处理这些事情的惯用方式。

但是,您可以做的是留在异步上下文中并处理其中的故障。 F# 提供(至少)两种常用的方法来处理这个问题。例如。您可以使用允许您编写管道的异步辅助函数:

let fetchAsyncPipeline (url: string) =
    FSharp.Data.Http.AsyncRequestString(url)
    |> Async.Catch
    |> Async.map (function
        | Choice1Of2 v -> Ok v
        | Choice2Of2 e -> Error e.Message)

不幸的是,Async.map 是 not yet包括。但是您可以像这样为自己定义它:

namespace global

[<RequireQualifiedAccess>]
module Async =

    let map f xA =
        async {
            let! x = xA
            return f x
        }

或者,您可以使用 F# 的 computation expressions提供语法糖以更命令式的方式编写上述内容:

let fetchAsyncCe (url: string) =
    async {
        try
            return!
                FSharp.Data.Http.AsyncRequestString(url)
                |> Async.map Ok
            with
            | e -> return Error e.Message
    }

在这两种解决方案中,我都将异常转换为 F# 的 result type,我个人认为这是处理错误的最佳方式。

最后,正如 brianberns 所指出的,您的表达式仅包含在 Async 中。类型。但是unlike C#的Task,异步计算代表程序如何计算一些东西,但是那个程序还没有启动,你必须显式地运行异步操作。一种方法是使用 Async.RunSynchronously:

Async.RunSynchronously (fetchAsyncCe "https://fsharpforfunandprofit.com/")

PS:您可能遇到过 Scott Wlaschin 的优秀 F# for fun and profit ,但如果你不这样做,你应该检查一下。就个人而言,我发现它是教你 F# 和函数式编程的最佳资源。

关于f# - 如何在 F# 中异步下载网页并捕获错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67342142/

相关文章:

f# - "id"字面量在哪里定义?

c# - Asp.net 核心 Blazor 服务器端 3.0 错误中的中间件重定向?

f# - 在 FsCheck 中生成自定义数据

Windows 10 上的 F# Sql 类型提供程序和 .NET Framework v4.0/4.5

c# - 使用类型提供程序和 JSON API

f# - 了解 F# 尾递归

.net - 如何在 F# 中声明对象数组?

f# - 类型 'XmlProvider' 未定义

csv - F# CSV 类型提供程序 : how to ignore some rows?

.net - F# 绑定(bind)重定向不适用于 F# 4.3.0-4.3.1