如何在 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"
我正在尝试使用可观察对象在 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"