我正在尝试将以下C#代码转换为F#。
static async Task<IEnumerable<string>> ListingObjectsAsync()
{
ListObjectsV2Request request = new ListObjectsV2Request
{
BucketName = bucketName,
MaxKeys = 10
};
ListObjectsV2Response response;
do
{
response = await client.ListObjectsV2Async(request);
foreach (S3Object entry in response.S3Objects)
{
yield return entry.Key;
}
request.ContinuationToken = response.NextContinuationToken;
} while (response.IsTruncated);
}
但是,以下未完成的代码出现了错误
错误FS0795使用'let!不允许在序列表达式中使用x = coll'。使用“ for coll中的x”代替。
let listObjects bucketName = async {
use client = new AmazonS3Client(RegionEndpoint.USEast2)
let request = new ListObjectsRequest(BucketName = bucketName, MaxKeys = 10)
// do while... todo
seq {
let! response = client.ListObjectsV2Async(request) |> Async.AwaitTask
for entry in response.S3Objects do
yield entry.Key
request.ContinuationToken <- response.NextContinuationToken
}
如何将C#do {...} while(...);
转换为F#btw?
答案 0 :(得分:9)
通常,您通常希望避免将一个计算表达式嵌套在另一个表达式中,因为它会使哪个表达式引用什么变得令人困惑。特别是在这里,您希望将let!
表达式解释为与async { let! foo = AsyncFoo() }
中相同,但正是seq { }
计算表达式正在解释let!
。
我建议将seq { }
拆分成自己的函数,并使用异步的循环部分。 listObjects
函数的其余部分不需要异步,
let keysFromPartialResponse response = seq {
for entry in response.S3Objects do
yield entry.Key
}
let doRequest request resultSoFar = async {
let! response = client.ListObjectsV2Async(request) |> Async.AwaitTask
request.ContinuationToken <- response.NextContinuationToken
let result = Seq.append resultSoFar (keysFromPartialResponse response)
if request.IsTruncated then
return! doRequest request result // This is the loop step
else
return result
}
let listObjects bucketName = async {
use client = new AmazonS3Client(RegionEndpoint.USEast2)
let request = new ListObjectsRequest(BucketName = bucketName, MaxKeys = 10)
return! doRequest request Seq.empty
}
使用AsyncSeq可能会有更好的解决方案,但我将其作为练习留给读者。
请注意,您的F#代码存在一个问题,该问题仍然存在于我的代码中,这是序列是惰性的,在被评估之前不会真正运行seq { ... }
代码。并且因为您使用过use
,所以一旦client
对象超出范围(即,一旦异步返回),就将处置AmazonS3Client
实例。因此,当您评估序列时(它将评估response.S3Objects
),客户端将不再有效。如果这意味着评估response.S3Objects
将失败,那么您将不得不将此代码转换为使用列表而不是seq。应该足够简单,所以我将其留给您,但是如果您有任何麻烦,请告诉我。