如何使用F#的rx扩展从简单值创建可观测值?

如何使用F#的rx扩展从简单值创建可观测值?,f#,rx.net,F#,Rx.net,目前,我有一个函数,从外部接收原始数据,对其进行处理,并将其发送到回调: let处理回调数据= 让数据=原始数据//转换为实际数据。。。。 回调数据 回调是一个函数'T->unit。具体地说,在我的例子中,它是MailboxProcessor的Post功能(被称为processmailbox.Post rawData) process函数被调用多次,每次我将处理后的数据推送到邮箱队列中。到目前为止还不错 现在,我想通过使用FSharp的rx扩展(FSharp.Control.Reactive)

目前,我有一个函数,从外部接收原始数据,对其进行处理,并将其发送到回调:

let处理回调数据=
让数据=原始数据//转换为实际数据。。。。
回调数据
回调是一个函数
'T->unit
。具体地说,在我的例子中,它是MailboxProcessor的
Post
功能(被称为
processmailbox.Post rawData
) process函数被调用多次,每次我将处理后的数据推送到邮箱队列中。到目前为止还不错

现在,我想通过使用FSharp的rx扩展(FSharp.Control.Reactive),以一种可以将处理后的数据发布给各种消费者的方式来更改此代码。这意味着
回调
将是一个可观察的函数,或者是一个发布给订阅者的函数。我该怎么做

我找到了两个选择:

  • 创建一个实现IObservable的类,并将该对象传递给
    进程
    函数。如果可能的话,我希望避免创建类

  • 使用
    主题.behavior
    。这正是我想要的,只是它需要一个初始状态,在这种情况下,这个初始状态在语义上没有意义,而且显然主题是不受欢迎的(来自ReactiveX站点的链接)


  • 从函数式编程的角度来看,哪种方法更好?有更好的方法吗?

    这里有一个想法:可以使用对象表达式实现
    IObservable
    ,而无需显式类的开销:

    let createObservable subscribe =
        {
            new IObservable<_> with
                member __.Subscribe(observer) =
                    subscribe observer
        }
    
    让createObservable订阅=
    {
    新IObservable与
    成员订阅(观察员)=
    订阅观察员
    }
    

    要使用它,请指定类型为
    IObserver->IDisposable
    subscribe
    函数。不需要上课。

    明白了。Fsharp reactive提供模块
    Fsharp.Control.reactive.Builders
    中的关键字
    observe
    。这允许您创建临时观察:

    open FSharp.Control.Reactive.Builders
    
    //In my real case, "initialData" is a byte stream and 
    //at each step I read a few bytes off of it
    let Process initialData =
        let rec loop data =
            observe {
                match data with
                | x :: xs ->
                    yield x
                    yield! loop xs
                | [] -> ()
            }
        loop initialData
    
    let obs = Process ([1;2;3;4;5])
    obs.Subscribe(fun d -> printfn "Consumer A: %A" d) |> ignore
    obs.Subscribe(fun d -> printfn "Consumer B: %A" d) |> ignore
    Threading.Thread.Sleep 1000
    obs.Subscribe(fun d -> printfn "Late consumer: %A" d) |> ignore
    
    

    重要的是要注意,这会创建一个冷的可观察对象,因此已故的使用者会接收所有事件。

    使用
    observe{..}
    计算生成器可以工作,但是
    FSharp.Control.Reactive
    库中有一个函数可以执行相同的操作:

    open FSharp.Control.Reactive
    let obs = Observable.ofSeq [1;2;3;4;5]
    
    如果我使用的是
    observe{..}
    computation builder,我还将使用它支持
    for
    循环这一事实,这使您的代码更加简单:

    let Process initialData = observe {
      for x in initialData do yield x }
    

    我在回答中使用了一个序列来举例说明,但在我的实际用例中,数据来自网络流。在这种情况下,我想我必须使用
    观察
    。很高兴知道!这可能不是一个好主意。用正确的Rx语义实现一个observable是很困难的,而且总是建议使用Rx的内置功能。你可能是对的,但这就是为什么我不喜欢反应式范例。太神奇了。这更多的是让并发代码安全地编写,这需要大量的检查和平衡——Rx作为monad抽象出线程和并发。