Clojure在州内的各州内部发布

我很想听听Clojure大师们对管理层级结构状态的建议。 我发现我经常使用{:structures {:like {:this {:with {:many 'levels}} } } }并且如果我想通过将原子围绕值(atom {:like (atom 'this)} ) ,我发现自己认为这一定是错的。 在顶层使用一个原子通常比较好,而在地图中没有任何值?


如果可能的话,不要在数据结构中使用嵌套原子。

主要原因是不变性是你的朋友。 Clojure是一种功能强大的语言,可以在不可变的数据结构上生长。 大多数库都假定不可变的数据结构。 Clojure的STM采用不可变的数据结构来获得最佳的并发性。 不变性使您有机会在任何一个瞬间拍摄整个状态的一致快照。 运行在不可变数据上的纯函数很容易开发和测试。

如果你把原子放在你的数据结构中,那么你失去了所有不变性的优点,并且会使你的代码变得非常复杂 - 如果它包含许多可变组件,就很难推断数据结构。

一些建议的替代方法:

  • 把你的整个数据结构放在一个参考或原子中。 这可能是一个巨大的数据结构,没有任何问题 - 我曾经写过一个游戏,其中整个游戏地图没有任何困难地保存在一个原子中。
  • 使用设计用于访问和更改嵌套的不可变数据结构的各种方法:关联,进入,更新等。
  • 使用递归函数来导航数据结构更加可管理。 如果结构中的一个节点具有相同“类型”的子节点,那么通常应该使用某种形式的递归函数,这通常是一个很好的暗示。

  • 您可以使用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你会更好。

    底线是,我不认为这两种方式都是“正确的方式”,它们都有其用法。


    这是Christophe Grand的博客文章,与这种设置的复杂性摔跤:http://clj-me.cgrand.net/2011/10/06/a-world-in-a-ref/

    链接地址: http://www.djcxy.com/p/66877.html

    上一篇: Clojure states within states within states

    下一篇: Idiomatic clojure map lookup by keyword