在无耻地从 Tomas Petricek 的博客中窃取了一段代码片段之后:
http://tomasp.net/blog/csharp-fsharp-async-intro.aspx
具体来说,这个(并对它进行了一些修改):
let downloadPage(url:string) (postData:string) = async {
let request = HttpWebRequest.Create(url)
// Asynchronously get response and dispose it when we're done
use! response = request.AsyncGetResponse()
use stream = response.GetResponseStream()
let temp = new MemoryStream()
let buffer = Array.zeroCreate 4096
// Loop that downloads page into a buffer (could use 'while'
// but recursion is more typical for functional language)
let rec download() = async {
let! count = stream.AsyncRead(buffer, 0, buffer.Length)
do! temp.AsyncWrite(buffer, 0, count)
if count > 0 then return! download() }
// Start the download asynchronously and handle results
do! download()
temp.Seek(0L, SeekOrigin.Begin) |> ignore
let html = (new StreamReader(temp)).ReadToEnd()
return html };;
我尝试用它执行以下操作,并在最后一行收到错误:
该类型预计具有 Async<'a>
类型,但具有 string ->改为 Asnyc<'a>
我在谷歌上搜索了该错误,但找不到任何可以揭示我的特定问题的内容。
let postData = "userid=" + userId + "&password=" + password + "&source=" + sourceId + "&version=" + version
let url = postUrlBase + "100/LogIn?" + postData
Async.RunSynchronously (downloadPage(url, postData));;
另外,我将如何修改代码,以便它异步下载非结束字节流(但在每个字节突发之间偶尔暂停)而不是字符串?当这个字节流通过时,我将如何集成读取它?我意识到这不仅仅是一个问题,但由于它们都密切相关,我认为一个问题会节省一些时间。
预先感谢,
鲍勃
P.S.由于我对 F# 还很陌生,请随时对我的代码进行任何更改/建议,以展示其如何以更实用的风格完成。我真的很想摆脱我的 C# 心态,所以我很感谢任何人希望分享的任何建议。
编辑:我不小心粘贴了我正在使用的错误片段。我确实对托马斯的片段进行了修改,但后来忘记了。
After shamelessly pilfering a code snippet from Tomas Petricek's Blog:
http://tomasp.net/blog/csharp-fsharp-async-intro.aspx
Specifically, this one (and making a few alterations to it):
let downloadPage(url:string) (postData:string) = async {
let request = HttpWebRequest.Create(url)
// Asynchronously get response and dispose it when we're done
use! response = request.AsyncGetResponse()
use stream = response.GetResponseStream()
let temp = new MemoryStream()
let buffer = Array.zeroCreate 4096
// Loop that downloads page into a buffer (could use 'while'
// but recursion is more typical for functional language)
let rec download() = async {
let! count = stream.AsyncRead(buffer, 0, buffer.Length)
do! temp.AsyncWrite(buffer, 0, count)
if count > 0 then return! download() }
// Start the download asynchronously and handle results
do! download()
temp.Seek(0L, SeekOrigin.Begin) |> ignore
let html = (new StreamReader(temp)).ReadToEnd()
return html };;
I tried to do the following with it, and got the error on the last line:
The type was expected to have type Async<'a>
but has string -> Asnyc<'a>
instead
I googled the error but couldn't find anything that revealed my particular issue.
let postData = "userid=" + userId + "&password=" + password + "&source=" + sourceId + "&version=" + version
let url = postUrlBase + "100/LogIn?" + postData
Async.RunSynchronously (downloadPage(url, postData));;
Also, how would I modify the code so that it downloads a non-ending byte stream (but with occasional pauses between each burst of bytes) asynchronously instead of a string? How would I integrate reading this byte stream as it comes through? I realize this is more than one question, but since they are are all closely related I figured one question would save some time.
Thanks in advance,
Bob
P.S. As I am still new to F# please feel free to make any alterations/suggestions to my code which shows how its done in a more functional style. I'm really trying to get out of my C# mindset, so I appreciate any pointers anyone may wish to share.
Edit: I accidentally pasted in the wrong snippet I was using. I did make an alteration to Tomas' snippet and forgot about it.
发布评论
评论(2)
当我尝试运行您的代码时,
downloadPage(url, postData)
不起作用,因为downloadPage
需要两个单独的字符串。downloadPage url postData
是预期的。如果您将
let
绑定更改为元组形式,或者let downloadPage(url:string, postData:string)
您的调用也会正常工作。要解释为什么会出现错误则更为复杂。柯里化形式创建一个返回函数或字符串 -> 的函数。字符串 ->在您的情况下为 Async 。因此,编译器看到您传递了一个参数(元组毕竟是单个项目),并看到结果必须是一个
string -> Async
与Async
不兼容。它可能发现的另一个错误(在我的例子中确实如此)是string * string
与string
不兼容。确切的错误是预期的字符串但发现'a * 'b
。When I attempt to run your code
downloadPage(url, postData)
doesn't work asdownloadPage
expects two seperate strings.downloadPage url postData
is what is expected.If you changed the
let
binding to tuple form, orlet downloadPage(url:string, postData:string)
your call would have worked as well.To explain why you got the error you got is more complicated. Curried form creates a function that returns a function or
string -> string -> Async<string>
in your case. The compiler therefore saw you passing a single parameter (tuples are single items after all) and saw that the result would have to be astring -> Async<string>
which is not compatible withAsync<string>
. Another error it could have found (and did in my case) is thatstring * string
is not compatible withstring
. The exact error beingExpected string but found 'a * 'b
.这就是我所拥有的:
这是持续随机猜测后有效的:
虽然,我不确定为什么这个更改解决了问题。想法?
This is what I had:
this is what worked after continued random guessing:
Although, I'm not sure why this change fixed the problem. Thoughts?