中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

F#與FRP怎么實現

發布時間:2022-01-10 11:12:41 來源:億速云 閱讀:128 作者:iii 欄目:編程語言

今天小編給大家分享一下F#與FRP怎么實現的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

這是一種較為優雅的基于事件的處理方式,適合一些如交互式動畫,自動控制方面的工作。即使平時不太常見,我想作為一個“嘗試”或“練習”也是非常合適的。

我是通過F#而了解“事件即對象”以及FRP的相關內容的,而微軟的Matthew Podwysocki最近一直在博客上撰寫的一系列關于F#事件的文章也給了我很多信息。F#便直接體現了“事件即對象”的概念,它會把.NET類庫中的事件轉化成IEvent對象,然后便可以對其進行編程。IEvent對象是F#中表示“事件”的標準類型,它的最關鍵的成員是Add方法,如果使用C#來表示便是:

public interface IEvent<TEventArgs>  {      void Add(Action<TEventArgs> callback);  }

當然,其實F#的事件并沒有那么簡單,不過我們目前只需要關注至此即可(更詳細的信息您可以關注Matthew的文章或Anders Cui同學的中文版)。Add方法是為這個事件添加一個回調函數,它自然會在事件觸發時被調用。而傳入的參數,您可看作是C#中事件的EventArgs對象(即第二個參數)。有了IEvent對象,在F#中便可以使用各種方式來響應一個事件。例如:

#light   open System  open System.Windows.Forms   let form = new Form(Visible = true, TopMost = true, Text =  form.MouseDown      |> Event.map (fun args -> (args.X, args.Y))      |> Event.filter (fun (x, y) -> x > 100 && y > 100)      |> Event.listen (fun (x, y) -> printfn "(%d, %d)" x y)

Event.map方法會接受一個IEvent對象,以及一個用于轉換事件參數的高階函數,并返回一個新的事件對象。用戶可以監聽這個新事件。當原有事件觸發時,它的事件參數將被高階函數轉化為新的對象,并以此出發新的事件。F#可以使用|>符號來改變參數傳遞的順序,這樣代碼可以編寫得更為流暢。例如下面兩行F#代碼其實是等價的:

Console.WriteLine "Hello World" "Hello World" |> Console.WriteLine

Event.filter的作用是對事件進行過濾,只有在原事件觸發時,其事件參數滿足某個條件,才會觸發新的事件對象。Event.listen則是簡單的調用IEvent對象的Add方法,它只是一個輔助函數。

F#的Event模塊還有其他一些方法,例如:

let form = new Form(Visible = true, TopMost = true, Text = "Event Sample")  form.MouseDown      |> Event.choose (fun args ->           if args.X > 100 && args.Y > 100 then Some(args.X, args.Y)           else None)      |> Event.listen (fun (x, y) -> printfn "(%d, %d)" x y)

Event.choose方法組合了Event.filter和Event.map,即在轉化的同時可進行過濾。只有在高接函數的返回值為Some(args)而不是None的時候,才把args作為下一個事件的參數進行觸發。還有:

let form = new Form(Visible = true, TopMost = true, Text = "Event Sample")  form.MouseDown      |> Event.merge form.MouseMove      |> Event.filter (fun args -> args.Button = MouseButtons.Left)      |> Event.map (fun args -> (args.X, args.Y))      |> Event.listen (fun (x, y) -> printfn "(%d, %d)" x y)

Event.merge方法的作用是合并兩個(參數相同的)事件。當其中任意一個事件觸發時,則會觸發新的事件對象。此外:

let form = new Form(Visible = true, TopMost = true, Text = "Event Sample")  let (overEvent, underEvent) =      form.MouseMove        |> Event.merge form.MouseDown        |> Event.filter (fun args -> args.Button = MouseButtons.Left)        |> Event.map (fun args -> (args.X, args.Y))        |> Event.partition (fun (x, y) -> x > 100 && y > 100)        overEvent |> Event.listen (fun (x, y) -> printfn "Over (%d, %d)" x y)  underEvent |> Event.listen (fun (x, y) -> printfn "Under (%d, %d)" x y)

Event.partition方法的作用是把原有事件拆分為兩個,并在原有事件被觸發時,根據高階函數的返回值來決定觸發哪一個新事件。

以上這些都是Matthew在博客中已經介紹過的內容。不過我認為,Event模塊下還有兩個方法值得一提,那就是Event.pairwise和Event.scan。請看下面的代碼:

let (trigger : (int -> unit), event) = Event.create()  event     |> Event.pairwise      |> Event.listen (fun (x, y) -> printfn "%d + %d = %d" x y (x + y))   [1..10] |> Seq.iter trigger // 使用1到10依次調用trigger

Event.create方法將創建一個事件對象,返回這個事件以及它的觸發器。Event.pairwise會根據IEvent<T>對象返回一個IEvent<(T, T)>對象——(T, T)是一個元組,當然在C#中沒有這個語言特性時,我們可以使用IEvent<T[]>來代替。當我們使用***次trigger方法來觸發event事件時,新的事件對象并不會觸發。直到第二次及以后觸發event事件時,才會把上一次的事件參數和目前的事件參數“合并”,并以此來觸發新的事件。因此,上面的代碼會輸出以下內容:

1 + 2 = 3 2 + 3 = 5 3 + 4 = 7 4 + 5 = 9 5 + 6 = 11 6 + 7 = 13 7 + 8 = 15 8 + 9 = 17 9 + 10 = 19

而Event.scan方法則可以這樣使用:

let (trigger : (int -> unit), event) = Event.create()  event     |> Event.scan (fun acc i -> acc + i) 0      |> Event.listen (printfn "%d")   [1..10] |> Seq.iter trigger

Event.scan方法會維護一個累加器(acc),在上面的代碼中其初始值為0,每次event事件觸發時,則會通過高階函數,把事件參數計算到當前的累加器中得到新的值,并根據新的值觸發新事件。因此上面的代碼會輸出一下內容(不包括注釋):

1 // +1  3 // +2  6 // +3  10 // ...  15  21  28  36  45  55

自然,Event.pairwise和Event.scan方法得到的新對象都是有side effect的,需要考慮線程安全的問題。F#的類庫不保證事件觸發時的線程安全,于是事件在使用或觸發時需要自行進行控制。

好,那么這次的“趣味編程”就產生了,您能否設計并實現一套類庫,為C#語言提供這樣一個類似的功能呢?您需要實現以下7種功能:
◆map
◆filter
◆choose
◆merge
◆partition
◆pairware
◆scan

有些朋友可能會想,為什么不直接使用C#來調用F#的類庫呢?原因是“不合適”。F#的類庫設計遵循了F#的語言特性,而且如前面所講,F#本身會對.NET的事件進行一定轉變。此外,為C#實現一個合適的API也是個很好的實踐過程。例如,這又是一個適合擴展方法特性的場景。在我看來,***的API應該是這樣使用的:

someEvent      .Map(args => new { args.X, args.Y })      .Filter(args => args.X + args.Y > 100)      .Scan(0, (acc, args) => acc + args.X, args.Y)      .Add(args => Console.WriteLine(args));

以上就是“F#與FRP怎么實現”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

frp
AI

九寨沟县| 涟水县| 江山市| 金阳县| 阿巴嘎旗| 阿拉尔市| 自贡市| 盐亭县| 金乡县| 洛川县| 衡山县| 赤峰市| 庄浪县| 海阳市| 新乐市| 沂水县| 九龙坡区| 集安市| 华容县| 泸水县| 大同市| 石城县| 台山市| 美姑县| 大竹县| 仪陇县| 理塘县| 邵阳县| 莱州市| 巴彦淖尔市| 黔西| 仁寿县| 盐城市| 五常市| 邮箱| 搜索| 石阡县| 鸡泽县| 武山县| 佳木斯市| 广安市|