F#滑动窗口代理无法处理记录

F#滑动窗口代理无法处理记录,f#,records,agent,observable,F#,Records,Agent,Observable,我一直在对Tomas Petricek编写的一个F#片段进行采样,该片段返回一个可观察到的结果,该结果产生了 包含从可观察的输入中提取的元素。当传递给函数的IObservable包含int或tuple时,这种方法可以很好地工作,但是如果它是一个IObservable记录,则“count”元素的每个结果数组(窗口)都包含相同的值。每个新窗口都包含上次观察到的值的相同“count”元素。下面重现了这个片段。异步表达式和F#记录之间是否存在可能导致这种行为的内部原因 open System modu

我一直在对Tomas Petricek编写的一个F#片段进行采样,该片段返回一个可观察到的结果,该结果产生了 包含从可观察的输入中提取的元素。当传递给函数的IObservable包含int或tuple时,这种方法可以很好地工作,但是如果它是一个IObservable记录,则“count”元素的每个结果数组(窗口)都包含相同的值。每个新窗口都包含上次观察到的值的相同“count”元素。下面重现了这个片段。异步表达式和F#记录之间是否存在可能导致这种行为的内部原因

open System

module Observable =

  /// Returns an observable that yields sliding windows of 
  /// containing elements drawn from the input observable. 
  /// Each window is returned as a fresh array.
  let windowed (count:int) (source:IObservable<_>) =
    { new IObservable<_> with
        member x.Subscribe(observer) =
          // Start an agent that remembers partial windows of length 
          // smaller than the count (new agent for every observer)
          let agent = MailboxProcessor.Start(fun agent ->
            // The parameter 'lists' contains partial lists and their lengths
            let rec loop lists = async { 
              // Receive the next value
              let! value = agent.Receive()

              // Add new empty list and then the new element to all lists.
              // Then split the lists into 'full' that should be sent
              // to the observer and 'partial' which need more elements.
              let full, partial =
                ((0, []) :: lists)
                |> List.map (fun (length, l) -> length + 1, value::l)
                |> List.partition (fun (length, l) -> length = count)

              // Send all full lists to the observer (as arrays)
              for (_, l) in full do
                observer.OnNext(l |> Array.ofSeq |> Array.rev) 
              // Continue looping with incomplete lists
              return! loop partial }

            // Start with an empty list of partial lists
            loop [])

          // Send incoming values to the agent
          source.Subscribe(agent.Post) }
开放系统
可观测模块=
///返回一个可观察值,该值生成
///包含从可观察的输入中提取的元素。
///每个窗口都作为新数组返回。
设置窗口(计数:int)(来源:IObservable)=
{新IObservable with
成员x.1(观察员)=
//启动一个代理,该代理会记住部分长度的窗口
//小于计数(每个观察者的新代理)
让代理=MailboxProcessor.Start(有趣的代理->
//参数“lists”包含部分列表及其长度
让rec循环列表=异步{
//接收下一个值
让!value=agent.Receive()
//添加新的空列表,然后将新元素添加到所有列表中。
//然后将列表拆分为应发送的“完整”
//对于需要更多元素的观察者和“部分”。
让全部,部分=
((0,[])::列表)
|>List.map(乐趣(长度,l)->长度+1,值::l)
|>List.partition(fun(长度,l)->length=count)
//将所有完整列表发送给观察者(作为数组)
对于(u,l)的完整do
observer.OnNext(l |>Array.ofSeq |>Array.rev)
//继续循环不完整的列表
return!循环部分}
//从部分列表的空列表开始
循环[])
//将传入值发送到代理
source.Subscribe(agent.Post)}

谢谢。似乎更简单的实现是使用System.Responsive,而不是MSDN上用于控制的文档中的ObservableSource的自定义实现。Observable确实可以按预期工作。然而,这个例子可能有一些问题

请在本文中提供一个简短的、可复制的例子来说明您的问题。这只是一个猜测,但可能与以下事实有关:记录是引用类型,而元组和整数是值类型。我相信ildjarn的意思是说元组是引用类型。(它们是参照类型。)@Curt:的确是!非常感谢。