F# asyncResult计算表达式中用do!调用retryAsync编译报错问题
报错原因
你遇到的类型不匹配问题核心是 asyncResult 计算表达式对 let! 和 do! 的类型约束不同:
- 你定义的
retryAsync<'a>返回类型为Async<'a>,第一次调用时传入的请求函数loadExchangeSettingsAsync rest返回类型是Async<Result<SettingsType, ExchangeError>>,因此泛型参数'a被推断为Result<SettingsType, ExchangeError>,retryAsync最终返回Async<Result<SettingsType, ExchangeError>>,正好符合let!对右侧表达式的类型要求,所以运行正常。 do!在asyncResult计算表达式中的约束是:右侧表达式必须返回Async<Result<unit, ExchangeError>>,即Result的成功分支类型必须是unit。你直接复用之前的retryAsync调用时,返回的成功分支类型还是你原来的配置类类型,和unit不匹配,因此触发编译器报错。
解决方案
有两种低成本的修改方式可选:
方案1:用let!绑定后丢弃返回值
不需要修改任何原有逻辑,只需要把do!换成let! _ = 即可,和你之前的正常调用逻辑完全一致:
asyncResult { let! _ = Retry.retryAsync Retry.shouldRetryExchange Retry.defaultRetryIntervals (fun r -> warn $"retry {r}/{Retry.defaultRetryIntervals.Length}") (fun _ -> loadExchangeSettingsAsync rest) ... return ... }
方案2:映射请求返回值为unit类型
如果你一定要用do!,可以把请求函数的返回结果的成功分支映射为unit,满足do!的类型约束:
asyncResult { do! Retry.retryAsync Retry.shouldRetryExchange Retry.defaultRetryIntervals (fun r -> warn $"retry {r}/{Retry.defaultRetryIntervals.Length}") (fun _ -> async { let! res = loadExchangeSettingsAsync rest return res |> Result.map ignore }) ... return ... }
内容的提问来源于stack exchange,提问作者Thomas
相关产品推荐
相关产品推荐

