簡體   English   中英

函數式編程中的共享資源

[英]Shared resource in functional programming

上下文

我正在使用Clojure編寫應用程序,並遵循函數式編程范例。 在這個應用程序中,我有兩個HTTP端點: /rank/invite /rank該應用會根據其得分對客戶的列表進行排名。 /invite該應用程序收到了一個客戶的邀請,從而邀請了另一個客戶,這將使某些客戶的分數發生變化。

問題

來自客戶的數據保存在一個稱為record的地圖矢量中。

暫且不提參考透明性, record應該是端點之間的共享資源,一個應讀取它並在排名函數中使用它來響應HTTP請求,另一個應讀取它並更新其中的分數。

現在,考慮到函數式編程,無法更新record ,因此/invite端點應該讀取它並返回新record' ,問題是, /rank端點已設置為使用record ,但是當生成新record'時,它應該用它代替原來的。

我解決這個問題的想法

我了解在這種情況下,整個應用程序在功能上不能完全純凈。 它從文件讀取初始輸入,並從外部環境接收請求,所有這些都使處理這些部分的功能不透明。 幾乎每個程序都將包含這些一小部分的非功能代碼,但是為了嘗試不向該應用程序添加更多這些非功能性代碼,並且該應用程序僅是為了執行一些功能性編程,所以我並沒有堅持record到數據庫之類的東西,因為如果是這種情況,則可以解決問題,因為我可以調用一個函數來更新數據庫上的記錄。

到目前為止,我最好的主意是:端點是使用Compojure的routes函數創建的,因此在/invite端點中,我應處理新record' vector,並重新創建/rank端點,並為其提供record' 我正在努力重建/rank這一部分,我試圖再次調用routes並再次定義所有端點,以希望它將覆蓋routes的原始調用,但是正如所料,我相信Compojure遵循函數式編程,一旦創建,路由是不可變的,並且路由的新調用不會覆蓋任何內容,它只會創建將留在空白中的新路由,而不附加到HTTP請求。

那么,有可能用純功能代碼做我想做的事嗎? 還是不可避免地要破壞參照透明性,我應該將record持久保存到文件或數據庫中以進行更新嗎?

PS:我不知道這是否相關,但是我對Clojure和任何類型的Web交互都是陌生的。

Clojure(與Haskell相反)不是純凈的,它具有自己的結構來管理對共享狀態的更改。 它不會使用類型系統(如Haskell中的IO monad)隔離不純,而是促進使用純函數並使用不同類型的引用( atomagentref )管理狀態,這些引用定義了明確的語義以及如何以及何時更改狀態。

對於您的方案,Clojure的atom將是最簡單的解決方案。 它就如何管理其狀態提供了明確的合同。

我將創建一個在原子內保存您的記錄的變量:

(def record (atom [])) ;; initial record is empty

然后,在rank終結點中,可以使用deref或將@用作語法糖來使用它的值:

(GET "/rank" []
  (calculate-rank @record))

而您的invite端點可以使用swap!原子地更新您的記錄值swap!

(POST "/invite/:id" [id]
  (invite id)
  (swap! record calculate-new-rank id)
  (create-response))

您的calculate-new-rank函數如下所示:

(defn calculate-new-rank [current-record id]
  ;; do some calculations
  ;; create a new record value and return it
  (let [new-record ...]
    new-record))

將使用存儲在atom中的數據的當前版本以及其他可選參數來調用您的函數,並且函數的結果將作為您的atom的新值安裝。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM