如何在 F# 中使用可观察对象

How to use observables in F#

我正在尝试使用可观察对象在 F# 中创建一个图形应用程序。到目前为止我的代码是:

open System.Windows.Forms
let form = new Form(Text="Test", TopMost=true)

let buttonNum0 = new Button(Text="1");
let buttonNum1 = new Button(Text="2", Top=20);
let buttonNum2 = new Button(Text="3", Top=40);
let buttonNum3 = new Button(Text="4", Top=60);

form.Controls.AddRange [| buttonNum0 ; buttonNum1; buttonNum2; buttonNum3 ; |]
let rec loop observable list = async{
            printList list

(Async.Await)
    let! somethingObservable = Async.AwaitObservable(observable) 

    match somethingObservable with
    | 0     -> return! loop observable ("0"::list)
    | 1     -> return! loop observable ("1"::list)
    | 2     -> return! loop observable ("2"::list)
    | 3     -> return! loop observable ("3"::list)
    | _     -> return! loop observable ("?"::list)
}
module GUIInterface = 
    //Here we define what we will be observing (clicks)
    let observables =
        Observable.merge 
        <| Observable.map (fun _-> 0) GUI.buttonNum0.Click 
        <| Observable.map (fun _-> 1) GUI.buttonNum1.Click              
        <| Observable.map (fun _-> 2) GUI.buttonNum2.Click 
        <| Observable.map (fun _-> 3) GUI.buttonNum3.Click

Async.StartImmediate(loop GUIInterface.observables []) ; System.Windows.Forms.Application.Run(GUI.form)

我尝试使用或多或少的 Observables,当我只使用其中两个(例如 0 和 1)时,它工作正常。 Observable.merge 只能使用 2 个 Observables 吗?有没有更好的方法来做到这一点,或者我如何使用多个可观察值?

凭借我平庸的搜索技巧,我在互联网上搜索了一些教程和参考资料,它们以简单的方式解释了可观察对象、反应函数式编程、.net 和 WinForms 的概念。如果您有任何指向好网站的链接,我很乐意拥有它们。 (试过 msdn(可能不是正确的部分?)和 http://fsharpforfunandprofit.com/posts/concurrency-reactive)

不确定为什么你的代码不起作用(我的猜测是它没有按照你期望的方式解析你的语法——使用圆括号而不是 backpipes 来使操作顺序更明确),但这适用于我的代码:

let btns = [GUI.buttonNum0; GUI.buttonNum1; GUI.buttonNum2; GUI.buttonNum3]
let observables = btns |> List.mapi(fun i btn -> Observable.map (fun _ -> i) btn.Click)
Observable.Merge observables

在进一步提高我的技能之后,我想出了另一个解决这个问题的方法。使用 FSharp.Control 时,您可以将两个可观察值合并为一个,然后重复此过程。因此,我提出的解决方案使用了它。通过使用递归,您可以遍历可观察对象,我决定将其放入列表中,首先将前两个放在一起,然后与下一个求和,依此类推。

备选答案:

let obsList = [ for x in 0..80 ->  (Observable.map (fun _-> x) ((Array.get(gameButtons)(x)).Click)) ]

let rec obsMerger obsList =
        match obsList with
        | x1::[] -> x1
        | x1::xs -> Observable.merge x1 (obsMerger xs)
        | [] -> failwith "No Observables"