基于同步调用构建在先前的question上,我们如何在以下场景中使用异步方法。
let fetch1 (result: string) : Result<string, string> =
try
use request = WebRequest.Create("http://bing.com") :?> HttpWebRequest
use response = request.GetResponse()
use reader = new StreamReader(response.GetResponseStream())
let html = reader.ReadToEnd()
Ok "success"
with
| :? WebException as e ->
Error "error with the url"
let fetch2 (result: string) : Result<string, string> =
try
use request = WebRequest.Create("http://google.com") :?> HttpWebRequest
use response = request.GetResponse()
use reader = new StreamReader(response.GetResponseStream())
let html = reader.ReadToEnd()
Ok "success"
with
| :? WebException as e ->
Error "error with the url"
let fetch3 (result: string) : Result<string, string> =
try
use request = WebRequest.Create("http://invalid.com") :?> HttpWebRequest
use response = request.GetResponse()
use reader = new StreamReader(response.GetResponseStream())
let html = reader.ReadToEnd()
Ok "success"
with
| :? WebException as e ->
Error "error with the url"
测试
let chain = fetch1 >> Result.bind fetch2 >> Result.bind fetch3
match chain("") with
| Ok message -> Debug.WriteLine(message)
| Error error -> Debug.WriteLine(error)
尝试
let fetch1 (result: string) :Result<string, string> = async {
try
use! request = WebRequest.Create("http://bing.com") :?> HttpWebRequest
use response = request.GetResponse()
use reader = new StreamReader(response.GetResponseStream())
let html = reader.ReadToEnd()
Ok "success"
with
| :? WebException as e ->
Error "error with the url"
}
错误
此表达式表示类型为&#39;结果&#39;但这里有类型&#39; Async&lt;&#39; a&gt;&#39;
答案 0 :(得分:2)
您应该解释一下您实际尝试在此实现的异常处理机制。对于很多东西,使用普通的F#内置异常将完美地运行。
您正在使用Result.bind
这是一种实现异常处理行为的方法,如果任何步骤抛出异常,则整体计算将失败。这是你想要达到的目标吗?如果是这样,您可以依靠内置的F#异步支持进行异常处理,并在异步计算中调用try .. with
来调用两个fetch
函数。一个最小的例子:
let fetch url = async {
use wc = new WebClient()
let! res = wc.AsyncDownloadString(System.Uri(url))
return res }
let fetchAllOrNothing = async {
try
let! goog = fetch "http://www.google.com"
let! bing = fetch "http://www.bing.com"
return Some(goog.Length, bing.Length)
with _ ->
return None }
如果你想调用所有的fetch函数并且只有当它们都失败时才会失败,那么你需要用异常处理程序包装各个fetch
函数(就像你一样),然后选择第一个结果。使用普通的F#选项类型,可以使用Array.tryPick
:
let fetch url = async {
try
use wc = new WebClient()
let! res = wc.AsyncDownloadString(System.Uri(url))
return Some res
with _ ->
return None }
let fetchFirstOne = async {
let! all =
[ fetch "http://www.google.com"
fetch "http://www.bing.com" ] |> Async.Parallel
return Array.tryPick (fun x -> x) all }
如果你是从F#开始,那么开始使用核心async
函数和选项之类的东西要容易得多 - 一旦你对它们感到满意,看看更复杂的方法是有意义的。 / p>