I'm learning F# and have a couple of routines much of whose functionality looks common so I am looking to refactor them together.
Here are the routines (which for the record I lifted from elsewhere:
let Prices time ID (polling:float) =
let sync = System.Threading.SynchronizationContext.Current
let obs = new Event<int>()
let raiseEvent (value:int) = sync.Post((fun _ -> obs.Trigger(value)), null)
let interval = TimeSpan.FromSeconds(polling)
let rec loop nextTime= async {
// Generate next value (on the GUI thread)
do getPrices nextTime
|> List.filter (fun price -> price.ID = ID)
|> List.iter (fun price -> raiseEvent price.Price)
// Wait some short time
do! Async.Sleep(1000)
// Continue looping
do! loop (nextTime.Add(interval)) }
loop time |> Async.Start
obs.Publish
and
let Volumes time ID (polling:float) =
let sync = System.Threading.SynchronizationContext.Current
let obs = new Event<VolumeDTO>()
let raiseEvent (value:VolumeDTO) = sync.Post((fun _ -> obs.Trigger(value)), null)
let interval = TimeSpan.FromSeconds(polling)
let rec loop nextTime= async {
// Generate next value (on the GUI thread)
do getVolumes nextTime
|> List.filter (fun volume -> volume.ID = ID)
|> List.iter (fun volume -> raiseEvent volume)
// Wait some short time
do! Async.Sleep(1000)
// Continue looping
do! loop (nextTime.Add(interval)) }
loop time |> Async.Start
obs.Publish
The external function calls are hopefully reasonable self explanatory retrieving data from a db
let getPrices lastTime =
createList<PriceDTO>((getPriceSql lastTime), priceReader)
let getVolumes lastTime =
createList<VolumeDTO>((getVolumeSql lastTime), volumeReader)
The types are very simple, but I'm not sure I've got this 'right':
type IID =
abstract member ID : int64
type PriceDTO(ID:int64, Price:int) =
interface IID with
member this.ID = ID
member x.ID = ID
member x.Price = Price
type VolumeDTO(ID:int64, Amount:decimal, Price:int32) =
interface IID with
member this.ID = ID
member x.ID = ID
member x.Amount = Amount
member x.Price = Price
I've played around with something but I'm not at all there as yet:
let publish<'a> time ID (polling:float) dataRetriever =
let sync = System.Threading.SynchronizationContext.Current
let obs = new Event<'a>()
let raiseEvent (value:'a) = sync.Post((fun _ -> obs.Trigger(value)), null)
let interval = TimeSpan.FromSeconds(polling)
let rec loop (nextTime:DateTime)= async {
// Generate next value (on the GUI thread)
do dataRetriever nextTime
|> List.filter (fun item -> item.ID = ID)
|> List.iter (fun item -> raiseEvent item)
// Wait some short time
do! Async.Sleep(1000)
// Continue looping
do! loop (nextTime.Add(interval)) }
loop time |> Async.Start
obs.Publish
I may well have not quite implemented this correctly. I'm obviously getting a list of prices or volumes filtering them and publishing them. In order to achieve the filtering I've created an interface, but I'm not really happy with this since I'd prefer to keep the DTOs as simple as possible. Intellisense is telling me that my dataRetriever
function takes a DateTime
and returns an 'a list, but I'm not sure I quite want that since I need to cast it to an IID interface for filtering and then back to the underlying DTO for publishing.
Is there a more 'functional' (or perhaps just better) way to do this?