函數式響應式編程
函數式響應式編程(FRP) 是一種編程範式,它採用函數式編程的基礎部件(如map、reduce、filter等),進行響應式編程(異步數據流程編程)。FRP被用於GUI、機械人和音樂方面的編程,旨在通過顯式的建模時間來簡化這些問題。
FRP的形式
[編輯]函數式響應編程,自從1997年由Conal Elliott和保羅·胡達客在ICFP 97論文《函數式響應式動畫》中提出以來[1],產生了多種形式。其多樣性的一條軸線,是離散與連續語義對比。另一條軸線,是怎樣讓FRP系統可以動態地更改。[2]
連續
[編輯]FRP的最早形式採用了連續的語義,旨在抽象出對程序的意義無關緊要的操作細節。[1]這種形式的關鍵屬性為:
- 建模在連續時間內變化的值,叫做「行為」,後來稱為「信號」。
- 建模「事件」,它發生在離散的時間點上。
- 系統可在響應事件時被改變,通用採用術語「切換」。
- 從響應模型中分離出求值細節,如採樣率。
這種FRP語義模型在無副作用的語言中通常採用隨時間變化的連續函數。[3]
離散
[編輯]如事件驅動FRP和Elm在0.17版本之前的那種形式,它們要求更新過程是離散的,且由事件驅動。[4]這些形式在FRP的實踐中被加以推崇,它們專注於擁有簡單API的語義,比如在機械人或Web瀏覽器中可以被高效地實現。[5]
在這些形式下,行為和事件的概念通常會被合併成信號,它總是擁有當前值,但會被離散地改變。[6]
交互式FRP
[編輯]Conal Elliott在2008年已經指出,從輸入到輸出,這種普通的FRP模型,不太適合交互式程序。[7]在從輸入映射到輸出的過程中缺乏「運行」程序的能力,可能意味着必須使用以下解決方案之一:
- 創建表示行動的一個數據結構,它表現為輸出。行動必須被一個外部的解釋器或環境來運行。它繼承了最初Haskell的流式I/O的全部難點。[8]
- 使用箭頭化的FRP,和有能力實行行動的嵌入箭頭。行動也必須有身份標識,比如說使得它們可以做維護各自的可變存儲。採取這種辦法的是Fudgets庫[9],和更一般性的單子流函數[10]。
- 最新穎的方法就是允許行動現在運行(於IO單子中),但將它們結果的接收推遲到以後。[11]它利用了事件和IO單子之間的交互,併兼容於更加面向表達式的FRP:
planNow :: Event (IO a) -> IO (Event a)
實現問題
[編輯]存在兩種類型的FRP系統,基於推送的和基於拉取的。基於推送的系統接收事件,並將它們推過一個信號網絡來達成結果。基於拉取的系統會等待對結果的需求,並逆向通過該網絡檢索所需求的值。
某些FRP系統例如Yampa使用採樣,這裏將採樣推過一個信號網絡。這種方法有個缺點:網絡在一個計算步驟持續期間必須等待,然後才能發現輸入上的變更。採樣就是個基於推送的FRP示例。
Hackage上的Reactive和Etage庫介入了一種叫做「推送-拉取FRP」的方式。按照這種方式,只在需求純粹定義的流(如隨時間推移的固定事件的列表)上的下一個事件時,才會構造該事件。這些純粹定義的流的行為類似於Haskell中的惰性列表。此為基於拉取的部分。基於推送的部分會在系統外部的事件被帶入系統時使用到。外部的事件會被推送給消費者,這樣它們就可以在它發佈的瞬間找到該事件。
實現
[編輯]- Yampa[12],是一個箭頭化、高效的、純Haskell實現,支持SDL、SDL2、OpenGL和HTML DOM。
- reflex[13],是一個高效的,用Haskell實現的推送/拉取式FRP,主要宿主是瀏覽器/DOM、SDL和Gloss。
- reactive-banana[14],是一個用Haskell實現的目標不可知的推送式FRP。
- netwire[15]和varying[16],是箭頭化的,用Haskell實現的拉取式FRP。
- Flapjax,是一個用JavaScript實現的行為/事件式FRP。
- React[17],是用於函數式響應編程的一個OCaml模塊。
- Sodium[18],是獨立於UI框架的推送式FRP實現,支持多種程式語言比如Java、TypeScript和C#。
- ReactiveX,由它的JavaScript實現rxjs[19]而流行,是實現函數式響應式編程的綜合性跨平台范型,將數據當作可觀測者的流來處理。
- Dunai[20],是支持類和箭頭化FPR的,使用單子流函數的一個Haskell的快速實現。
另請參閱
[編輯]參考來源
[編輯]- ^ 1.0 1.1 Elliott, Conal; Hudak, Paul, Functional Reactive Animation, ICFP, 1997 [2018-04-13], (原始內容存檔於2020-11-11).
- ^ Nilsson, Henrik; Courtney, Antony; Peterson, John, Functional Reactive Programming, Continued (PDF), Haskell Workshop (PDF) (2), Feb 2011 [2002] [2018-04-13], (原始內容 (PDF)存檔於2017-10-10).
- ^ Courtney, Antony; Elliott, Conal, Genuinely Functional User Interfaces, Haskell Workshop, Yale, Feb 2011 [2001] [2018-04-13], (原始內容存檔於2022-04-13).
- ^ Taha, Walid; Wan, Zhanyong; Hudak, Paul, Event-Driven FRP, PADL, Yale, 2002 [2021-03-02], (原始內容存檔於2021-02-10).
- ^ Czaplicki, Evan; Chong, Stephen, Asynchronous Functional Reactive Programming for GUIs, PLDI, Harvard, 2013 [2018-04-13], (原始內容存檔於2018-11-09).
- ^ Wan, Zhanyong; Taha, Walid; Hudak, Paul, Real-Time FRP, ICFP (PDF) (1), Feb 2011.
- ^ Why classic FRP does not fit interactive behavior. [2018-04-13]. (原始內容存檔於2015-07-24).
- ^ Alan Borning1CSE 505I/O in Purely Functional Languages (PDF). [2018-04-13]. (原始內容存檔 (PDF)於2016-05-28).
- ^ The Fudgets Thesis on WWW. [2018-04-13]. (原始內容存檔於2020-01-24).
- ^ Perez, Ivan; Barenz, Manuel; Nilsson, Henrik, Functional Reactive Programming, Refactored, Haskell Symposium (PDF), July 2016 [2021-03-02], (原始內容存檔 (PDF)於2017-05-18).
- ^ Atze van der Ploeg; Koen Claessen. Practical Principled FRP-Forget the past, change the future, FRPNow!. [2021-03-04]. (原始內容存檔於2020-04-25).
- ^ Yampa. [2021-03-02]. (原始內容存檔於2021-03-01).
- ^ reflex. [2018-04-13]. (原始內容存檔於2020-11-11).
- ^ reactive-banana. [2018-04-13]. (原始內容存檔於2020-11-11).
- ^ netwire. [2018-04-13]. (原始內容存檔於2020-10-20).
- ^ varying. [2018-04-13]. (原始內容存檔於2020-11-12).
- ^ React. [2021-03-02]. (原始內容存檔於2020-12-24).
- ^ Sodium. [2021-03-02]. (原始內容存檔於2020-12-24).
- ^ rxjs. [2021-03-02]. (原始內容存檔於2021-05-17).
- ^ Dunai. [2021-03-02]. (原始內容存檔於2021-05-24).
- ^ Czaplicki, Evan, Elm: Concurrent FRP for Functional GUIs (PDF) (thesis), Harvard, Apr 2012 [2021-03-02], (原始內容存檔 (PDF)於2021-04-16).
- ^ Czaplicki, Evan. A Farewell to FRP. elm. [14 July 2018]. (原始內容存檔於2019-05-31).
外部連結
[編輯]- cellx(頁面存檔備份,存於互聯網檔案館) – 一個 JavaScript 實現的超快速反應式庫
- Haskell 相關的 FRP(頁面存檔備份,存於互聯網檔案館) 研究
- "Deprecating the Observer Pattern with Scala.React(頁面存檔備份,存於互聯網檔案館)," – Scala.React, 一個 FRP 的 Scala 實現
- probability of living chart example - 使用ReactiveChart FRP 的無毛刺實現,詳見文檔 https://web.archive.org/web/20170927112527/https://reactivechart.com/knowledge/reactive/
- What is (functional) reactive programming?(頁面存檔備份,存於互聯網檔案館) – Stack Overflow 的問答