簡體   English   中英

Clojure在州內的州內陳述

[英]Clojure states within states within states

我很想聽聽Clojure大師們在層次結構中管理狀態的建議。 我發現我經常使用{:structures {:like {:this {:with {:many 'levels}} } } }如果我想跟蹤多個級別的狀態變化,可以通過在值周圍拋出原子(atom {:like (atom 'this)} ) ,我發現自己認為這一定是錯的。 通常最好只在頂層使用一個原子,並且在地圖中沒有任何值作為值?

如果可能的話,不要在數據結構中使用嵌套原子。

主要原因是不變性是你的朋友。 Clojure是一種在不可變數據結構上蓬勃發展的函數式語言。 大多數庫都采用不可變的數據結構。 Clojure的STM采用不可變數據結構來獲得最佳的並發性。 不變性使您有機會在任何一個瞬間拍攝整個州的一致快照。 對不可變數據進行操作的純函數易於開發和測試。

如果將原子放入數據結構中,那么就會失去不可變性的所有優點,並且會使代碼變得非常復雜 - 如果數據結構包含大量可變組件,則要更加難以推理數據結構。

一些建議的替代方法:

  • 將整個數據結構放在一個ref或atom中。 這可能是一個巨大的數據結構,沒有任何問題 - 我曾經寫過一個游戲,整個游戲地圖都在一個原子中沒有任何困難。
  • 使用旨在訪問和更改嵌套不可變數據結構的各種方法: assoc-inget-inupdate-in等。
  • 使用遞歸函數使您的數據結構導航更易於管理。 如果你的結構中的一個節點具有相同“類型”的子節點,那么通常你應該使用某種形式的遞歸函數。

您可以使用assoc-inget-inupdate-indissoc-in函數來處理嵌套結構。

它們非常方便,但我不知道它們是否可以直接處理原子等。 在最壞的情況下,您應該能夠將它們嵌套到deref,例如:

(def m (atom {:like {:this {:nested (atom {:value 5})}}}))

@(get-in @m [:like :this :nested])
; => {:value 5}

(get-in @(get-in @m [:like :this :nested]) [:value])
; => 5

您可以使用->使其更具可讀性:

(-> @m
    (get-in [:like :this :nested])
    deref
    (get-in [:value]))
; => 5

關於嵌套的原子/參考/代理等,我認為這取決於你想要實現的目標。 如果只有其中一個位於頂部並且更改是同步的,那么推理事物肯定更容易。

另一方面,如果你不需要這種同步,你就會浪費時間去做,而你最好使用嵌套的atoms / refs / agents。

最重要的是,我認為無論哪種方式都是“正確的方式”,它們都有其用途。

我更喜歡在頂級使用一個原子,因為這會使事情變得非常簡單,並且還表明數據代表一個狀態,該狀態由操作立即修改。 如果你把原子放在每個層次上,那么它就會變得太復雜而無法弄清楚發生了什么。 另外,如果你的情況下嵌套方式太深,我建議你坐下來仔細考慮是否需要這樣的結構,或者可以有更好的替代方案,因為這肯定會導致復雜性,直到嵌套數據遞歸為止(即每個級別的結構相同)

暫無
暫無

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

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