[英]how can I 'de-uglify' these nested async parts, in F#
first, here is the code:首先,这里是代码:
let getCandlesFromAsync (exchange: IExchange) (instrument: Instrument) (interval: TimeSpan) (fromTime: DateTime) (toTime: DateTime) =
async {
let rec getAsync (c: CandleData list) (f: DateTime) (t: DateTime) =
async {
//info $"requesting {instrument}: {f} - {t}"
let! candles = exchange.GetCandlesAsync(instrument, interval, f, t)
if candles.IsError then
return (failwith candles.GetError.Describe)
else
//info $"received data {instrument}: {candles.Get.[0].Timestamp} - {candles.Get.[^0].Timestamp}"
let c = c @ candles.Get
if c.[^0].Timestamp < t - interval then
return! getAsync c (c.[^0].Timestamp + interval) t
else
return c
}
let cache = DataCache.getCache instrument
let candlesFromCache = getCandlesFromCache cache interval fromTime toTime
let firstTimestamp =
match candlesFromCache.IsEmpty with
| true -> fromTime
| false -> candlesFromCache.[^0].Timestamp + interval
// check if we need some new data
let downloadedCandles =
async {
if firstTimestamp < toTime then
let! x = getAsync [] firstTimestamp toTime
putCandlesInCache cache x
return x
else
return []
}
let! d = downloadedCandles
return candlesFromCache @ d
}
This code is supposed to download price candles from an exchange.此代码应该从交易所下载价格蜡烛。 It has to run at regular interval and catch up with the new data.它必须定期运行并赶上新数据。
Since I need data from a range of timestamps, I try to cache the data that has previously been requested from the exchange.由于我需要来自一系列时间戳的数据,因此我尝试缓存之前从交易所请求的数据。 At the range is always moving forward, I only have to check how much data I already have in the range, and how much I need to get.在范围内总是向前发展,我只需要检查范围内我已经拥有多少数据,以及我需要获得多少。
The code is split into several parts:代码分为几个部分:
The issue here is that the whole function is expected to be async, but getAsync is recursive, so it has its own async block.这里的问题是整个 function 预计是异步的,但 getAsync 是递归的,所以它有自己的异步块。 Then the code that glues things together has to call getAsync and attach the data to what comes from the cache, so the whole thing is wrapped in an async block as well...然后将事物粘合在一起的代码必须调用 getAsync 并将数据附加到来自缓存的数据,因此整个事物也被包装在一个异步块中......
There has to be a cleaner way to do this, but I'm not sure how.必须有一种更清洁的方法来做到这一点,但我不确定如何。 Any suggestions would be welcome!欢迎大家提出意见!
Separating the functions is the best practice.分离功能是最佳实践。 It doesn't necessarily reduce the number of async
s but it makes the code cleaner and easier to understand.它不一定会减少async
的数量,但它会使代码更清晰,更易于理解。
The function that downloads from exchange may be on its own:从交易所下载的 function 可能是独立的:
let downloadFromExchange (exchange: IExchange) (instrument: Instrument) (interval: TimeSpan) (f: DateTime) (t: DateTime) =
let rec getAsync (previousCandles: CandleData list) (f: DateTime) =
async {
//info $"requesting {instrument}: {f} - {t}"
if f < t then return previousCandles else
let! candles = exchange.GetCandlesAsync(instrument, interval, f, t)
if candles.IsError then
return (failwith candles.GetError.Describe)
else
//info $"received data {instrument}: {candles.Get.[0].Timestamp} - {candles.Get.[^0].Timestamp}"
let c = previousCandles @ candles.Get
match c.[^0].Timestamp + interval with
| fr when fr < t -> return! getAsync c fr
| _ -> return c
}
getAsync [] f
I changed the code a little bit to make it clearer for me.我稍微更改了代码以使其更清楚。 I could be wrong but it seems to me the expression c.[^0].Timestamp
may result in an exception (or an infinite loop) if the list is empty either in the first call or in a recursive invocation.我可能是错的,但在我看来,如果列表在第一次调用或递归调用中为空,则表达式c.[^0].Timestamp
可能会导致异常(或无限循环)。
let getCandlesFromAsync exchange (instrument: Instrument) (interval: TimeSpan) (fromTime: DateTime) (toTime: DateTime) =
async {
let cache = DataCache.getCache instrument
let candlesFromCache = getCandlesFromCache cache interval fromTime toTime
let firstTimestamp =
match candlesFromCache.IsEmpty with
| true -> fromTime
| false -> candlesFromCache.[^0].Timestamp + interval
let! x = downloadFromExchange exchange instrument interval firstTimestamp toTime
putCandlesInCache cache x
return candlesFromCache @ x
}
I put the condition from < to
in the download function, that way the code is cleaner.我将条件from < to
下载 function 中,这样代码更干净。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.