用于存储跟踪信息的可变列表的替代方案

时间:2013-12-05 14:05:56

标签: f# immutability generic-collections

我有一些计算。 在这个例子中,一个非常简单的循环是for循环。实际上,在测试之后,我将有一个循环来处理实时流数据。

open System.Collections.Generic

let updates = new List<int>()

let appendToAList number = 
    updates.Add number
    printfn "Added: %i" number

let test = 
    for num in [1..100] do
        appendToAList num
        num * 2 |> ignore

我的目标是实现appendToAList,这个函数可以获取有关正在进行的计算的一些额外信息(跟踪其执行所需的信息),并将结果堆叠在合适的数据结构中。是否有可变列表的功能替代?

谢谢。

编辑:有关achitecture的更多信息

不确定这会有所帮助,但是 - 长话短说 - 我正在建立一个交易系统。

我的代码中的一些片段:

// defines the action steps when new data is received
let processFeed (date, feed:Matrix) = stateMonad<Matrix, Matrix> {
    do! strategy.ApplyPnL feed 
    do! strategy.RecalibrateFilter feed 
    let! signal' = strategy.Signal feed 
    do! strategy.Trade feed signal' }

此部分采用时间戳和新鲜市场报价。 Strategy包含了一些数学函数。根据客户需求,该策略可以重新校准,提取信号并最终拍摄订单。为了使事情更精简,状态monad带有算法和投资组合的状态(金钱,股票等)。

目前,我必须运行模拟(回测)以评估事情是否正常。基本上,我遍历历史数据。

// process the historical data
let rows = seq {  for idx = 0 to 3 do yield (dataframe.GetRowKeyAt(idx), data.[[idx], [0..3]])  }  // for debugging purposes here I have replaced data.Size.[0]-1 with 3
let simulation = stateMonad<Matrix, Matrix> {
    for row in rows do
        do! processFeed row }

for循环中运行的完全相同的代码将来应该在一个看起来像

的循环中运行
...
let runLive = 
    while (isConnected) 
        let newFeed = GetSomehowDataFromTheMarket
        do! processFeed newFeed

我还没有解决这个问题,我正在学习F#,请原谅这个无意义的伪代码。

我需要的是一种巧妙的方法,可以从循环中获取信息并对其进行处理(以gui显示,绘制一些数据等)。换句话说,我需要草拟算法将如何向用户报告。

我已经开始尝试将算法的状态堆叠在一个列表中,这样我最终可以开始绘制一些东西。

如果我可以运行在单独的线程上处理报告的函数,那将是很好的,所以我有兴趣学习一种功能性的方法来完成所有这些,这有助于设计易于并行化的东西。

3 个答案:

答案 0 :(得分:1)

最好删除你的循环并做这样的事情(除非你的其他要求阻止它):

let test = [1..100] |> List.fold (fun state number-> printfn "Added: %i" number
                                                     number::state) []

F#标准列表(与List中的System.Collections.Generic类型不同)是不可变的。另外,请注意不再有任何可变变量。如果您不熟悉F#列表类型,[]会创建一个空列表,并在项目和列表之间放置::会创建一个包含该项目的新列表。

答案 1 :(得分:1)

即使你有一些全局状态(例如某些实时流产生的值),使用 immutable 功能列表也可能有意义,但有一个可变引用。

这个想法是,你可以非常便宜地附加元素(在前面),并且在任何时候,你都可以安全地获得对当前列表的引用(并且同时处理它,同时构造新状态 - 没有影响处理列表早期快照的进程。)

所以你可以使用类似的东西:

let mutable updates = []

let appendToAList number = 
    updates <- number::updates
    printfn "Added: %i" number

let test = 
    for num in [1..100] do
        appendToAList num
        num * 2 |> ignore

最佳选择实际上取决于您考虑的实际情况 - 因此,如果您想获得更好的答案,请尝试描述您正在设计的系统/架构。

答案 2 :(得分:1)

如果我正在处理实时数据流的处理,我可能会使用某种事件流解决方案,其中每个计算的结果触发一个事件。

根据计算结果(可能存在错误或特定范围内的值的特殊情况等),您可以使用Observable模块构建具有特定规则等的事件管道。您的管道可以通过将结果和时间信息存储在数据库中,或者绘制到UI或其他内容来结束。

这样你就可以完全取消你的可变状态。

let event = new Event<int>()
let observable = event.Publish

// Example rules: Even numbers are successes and odd numbers are errors
let evens, odds = observable |> Observable.partition (fun i -> i%2=0)
evens |> Observable.subscribe (printfn "Success: %i")
odds |> Observable.subscribe (printfn "Error: %i")


let appendToList number = 
    event.Trigger(number)

let test = 
    for num in [1..100] do
        appendToList num
        num * 2 |> ignore

这可能完全不合适,也许您需要适合某种设计才能插入现有系统或其他任何系统。但话说回来,它也可能有所帮助! - 希望是后者。