【问题标题】:Clojure: working with refs in a collectionClojure:在集合中使用 refs
【发布时间】:2017-01-14 20:23:15
【问题描述】:

我正在与裁判一起工作,我需要一些帮助。

我在这里有 2 个银行账户,分别是 :operations

    (ref :name "bank"
         :accounts 
        {12345678 (ref {:name "joey" 
                       :account-number 12345678 
                       :operations (ref {:desc "DESC1" :amount 100 :date "2017-01-10"]})
                                   (ref {:desc "DESC2" :amount 200 :date "2017-01-11"]})
                                   (ref {:desc "DESC3" :amount 300 :date "2017-01-12"]})})
        {87654321 (ref {:name "paul" 
                       :account-number 12345678 
                       :operations (ref {:desc "DESC1" :amount 50 :date "2017-01-10"]})
                                   (ref {:desc "DESC2" :amount 10 :date "2017-01-11"]})
                                   (ref {:desc "DESC3" :amount 30 :date "2017-01-12"]})})
})

我需要从所有帐户中获取所有 :operations 来构建这样的集合:

[{:desc "DESC1" :amount 100 :date "2017-01-10"]}
 {:desc "DESC2" :amount 200 :date "2017-01-11"]}
 {:desc "DESC3" :amount 300 :date "2017-01-12"]}
 {:desc "DESC1" :amount 50 :date "2017-01-10"]}
 {:desc "DESC2" :amount 10 :date "2017-01-11"]}
 {:desc "DESC3" :amount 30 :date "2017-01-12"]}]

不需要相同,这只是一个想法,我正在尝试使用 mapderef 但仍然卡住了。

【问题讨论】:

  • 我感觉(ref :name "bank")无效,对吧?
  • 你尝试过什么,你被卡住了吗?顺便说一句,您的代码甚至无法读取(“不匹配的分隔符”),更不用说工作了。
  • 两件事:请告诉我这不是实际的银行代码。 :P 并告诉我们更多关于为什么您的数据看起来像这样的原因。三重嵌套的 refs 有一种代码味道。

标签: dictionary vector clojure ref


【解决方案1】:

您的代码有很多问题需要解决。虽然 clojure 对并行性/并发性有很好的支持,但您首先需要掌握基础知识。处理多个活动线程是很困难的,试图做到这一点,同时试图弄清楚基本数据结构和核心功能是如何工作的,这几乎是不可能的。

  1. 您的 ref 函数不是有效的 clojure。参考状态的文档

ref 函数用法:(ref x) (ref x & options) 创建并返回一个初始值为 x 和零个或多个选项(以任意顺序)的 Ref:

:元元数据映射

:validator validate-fn

:min-history (默认0) :max-history (默认10)

如果提供了 metadata-map,它将成为 ref 上的元数据。 validate-fn 必须为 nil 或一个参数的无副作用 fn, 这将在任何状态更改时传递预期的新状态。如果 新状态是不可接受的,validate-fn 应该返回 false 或 抛出异常。 validate-fn 将在事务提交时调用, 当所有 ref 都有其最终值时。

通常 refs 会根据需要动态累积历史来处理 阅读要求。如果您提前知道,您将需要历史记录,您可以设置 :min-history 以确保它在第一次需要时可用(而不是 读故障后)。历史是有限的,限制是可以设定的 与:最大历史。在 Clojure 1.0 版中添加

您在开始时使用的两个关键字看起来可能正在尝试为 ref 定义元数据。您需要在定义 ref 时使用 :meta 选项(这是我对您真正意图的猜测,可能完全不正确)。

  • ref 的强制参数是初始值。这需要是一个有效的 clojure '结构'或返回一个的函数。在您的情况下,您看起来想要一张地图。

    1. 我认为您不需要嵌套引用。虽然从技术上讲,我认为您可以定义它们,但这几乎肯定不是您真正想要的。阅读refs and transactions,了解您可能不想这样做的原因以及它对执行 STM 的影响。一般的经验法则是隔离您需要确保管理的值。您需要细粒度的访问控制,并且希望避免嵌套访问控制,因为它会使事情变得过于复杂,并且您的访问控制将变得更加精细。考虑您的银行账户操作。您不想在仅对其中一个或两个银行账户进行操作时锁定所有银行账户——您只想锁定/控制所涉及账户的更新。您可能想要的是一个 refs 数组(向量),或者一个普通的哈希映射,其中一个键是帐户,值是 ref,它又是一个映射,其中包含您需要确保更新的值一个事务(其他选项将包括信号量或临界区方法,而 ref 是一个简单的标志/锁,用于确定事务是否可以继续或必须回滚并再次尝试。

    2. 我认为您可能需要多考虑一下您的数据结构。稍微玩一下哈希映射并尝试嵌套结构。使用那些基本和嵌套数据结构(map、filter、reduce、loop/recur、sequence 和 laziness 等)的核心功能。正确获取基本抽象,然后看看你需要如何更改它以确保你的一致性数据,即如何确保您的交易具有适当的原子性,尤其是在涉及多个帐户时。您当前的嵌套结构无效 - 例如,查看 :operations 值。那是什么值?它是交易参考的向量吗?如何clojure 知道这是一个向量吗?您的应用程序需要如何提取该数据?最频繁的操作是什么——将它们全部提取在一起或提取单个事务?它们需要按日期顺序排列吗?获得特定日期的交易?一旦你有数百个账户和数千笔交易,这个规模会扩大吗?等等。正确地抽象,容易的事情仍然很容易。错了,容易的事情会变得困难,困难的事情ngs 可能会更难。

【讨论】:

    猜你喜欢
    • 2010-11-05
    • 1970-01-01
    • 2014-11-02
    • 2017-11-11
    • 1970-01-01
    • 2016-02-15
    • 1970-01-01
    • 1970-01-01
    • 2013-09-27
    相关资源
    最近更新 更多