版權歸原作者所有,如有侵權,請聯(lián)系我們

[科普中國]-函數(shù)式反應式編程

科學百科
原創(chuàng)
科學百科為用戶提供權威科普內容,打造知識科普陣地
收藏

函數(shù)式編程(functional programming)或稱函數(shù)程序設計,又稱泛函編程,是一種編程典范,它將計算機運算視為數(shù)學上的函數(shù)計算,并且避免使用程序狀態(tài)以及易變對象。函數(shù)式反應式編程(FRP) 是一種采用函數(shù)式編程的基礎部件(如 map、reduce、filter 等)進行反應式編程(異步數(shù)據流編程)的編程范式。FRP 被用于GUI、機器人和音樂方面的編程,旨在通過明確時間模型來簡化這些問題。

簡介函數(shù)式編程是一種編程范式, 它將計算機運算視為數(shù)學上的函數(shù)計算。 函數(shù)式編程的基礎是 lambda 演算。可是,單純依靠這兩句解釋是不足以分辨函數(shù)式編程跟其他編程范式的不同之處, 這需要結合函數(shù)式編程語言的特性去分析。 首先, 函數(shù)式編程中的函數(shù)指的是“高階函數(shù)”, 即函數(shù)可以作為參數(shù)傳入到其他函數(shù), 函數(shù)也可以返回函數(shù)作為結果1。

函數(shù)式反應式編程自1997 年 FRP 被提出以來,它產生了多種形式。其中一條多樣性的坐標軸是語義從離散到連續(xù)。 另一條軸是 FRP 系統(tǒng)可以如何被動態(tài)地更改。

如事件驅動 FRP 和 Elm 0.17 版本之前的形式那樣,它們要求更新過程是離散的,且由事件驅動。這些形式在 FRP 的實踐中被加以推崇,它們專注于擁有簡單 API 的語義,可以在如機器人學或 Web 瀏覽器中被高效地實現(xiàn)。在這些形式下,行為和事件的概念通常會被組合成總是擁有當前值的信號,但是它會被離散地改變。FRP 的最早形式采用了連續(xù)的語義,旨在抽象出對程序的意義無關緊要的操作細節(jié)。這種形式的關鍵屬性為:

建模值在連續(xù)時間內變化,叫做“行為”,后稱為“信號”。

建模“事件”發(fā)生在離散的時間點上。

系統(tǒng)可在相應事件時被改變,通用術語為“切換”。

從反應模型中分離出求值細節(jié),如采樣率。

這種 FRP 的語義模型在無副作用的語言中通常是隨時間變化的連續(xù)函數(shù)。

交互式 FRP需要被指出的是,普通的 FRP 模型,從輸入到輸出都不太適合交互式程序。在從輸入映射到輸出的過程中缺乏“運行”程序的能力可能意味著必須使用以下解決方案之一:

創(chuàng)建一個用于輸出的數(shù)據結構來表示活動。活動必須被一個外部的解釋器或環(huán)境來運行。它繼承了最初 Haskell 的流式 I/O 的全部難點。

使用箭頭化的 FRP 并嵌入能夠處理動作的箭頭?;顒右脖仨氁蠭D,以便讓它們分別維護不可變存儲之類的東西。這就是 Fudgets 庫采取的辦法。

最新穎的方法就是允許活動運行在(在 IO 單子中)但將它們結果的接收推遲到之后。它采用了事件 Event 和 IO 單子之間的交互,并與更加面向表達式的 FRP 兼容:

planNow :: Event (IO a) -> IO (Event a)實現(xiàn)存在兩種類型的 FRP 系統(tǒng),基于推送的和基于拉取的?;谕扑偷南到y(tǒng)接收事件并將它們推過一個信號網絡來達到某種結果。基于拉取的系統(tǒng)會等待結果請求,并逆向通過該網絡來取回請求的結果。

某些 FRP 系統(tǒng)例如 Yampa 使用采樣。在一個定期內,采樣被推過一個信號網絡。這種方法有兩個缺點:在一個定期內處理樣本的計算量會非常大,而且網絡必須在等待采樣區(qū)間的間隔時找出輸入的更改。采樣就是個基于推送的 FRP 示例。

Hackage 上的 Reactive 和 Etage 庫介紹了一種叫做“推送-拉取 FRP” 的方式,它將基于推送和基于拉取的 FRP 最好的部分結合在了一起。按照這種方式,只有在定義純粹的流上(如一系列時間固定的事件)的下一個事件被請求時,才會構造該事件。這些定義純粹的流的行為類似于 Haskell 中的惰性列表。此為基于拉取的部分。基于推送的部分會在系統(tǒng)外部的事件被帶入系統(tǒng)中時才會使用。外部的事件會被推送給消費者,這樣它們就可以在它發(fā)布的瞬間找到該事件。

reflex 是一個高效的,用 Haskell 實現(xiàn)的推送/拉取式 FRP,主要用于瀏覽器/DOM、SDL 和 Gloss

reactive-banana 是一個用 Haskell 實現(xiàn)的目標不可知的推送式 FRP

netwire 和 varying 是被箭頭化的,用 Haskell 實現(xiàn)的拉取式 FRP

Flapjax 是一個用 JavaScript 實現(xiàn)的行為/事件式 FRP

本詞條內容貢獻者為:

王沛 - 副教授、副研究員 - 中國科學院工程熱物理研究所