Clojure:使用集合中的引用
Clojure: working with refs in a collection
我正在与 refs 打交道,我需要一些帮助。
我这里有 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"]}]
不需要相同,这只是一个想法,我正在尝试使用 map
和 deref
,但仍然卡住了。
您的代码有很多问题需要解决。虽然 clojure 对 parallelism/concurrency 有很好的支持,但您需要先掌握正确的基础知识。处理 activity 的多个线程是困难的,试图做到这一点的同时还要尝试弄清楚基本数据结构和核心函数的工作原理几乎是不可能的。
- 您的 ref 函数不是有效的 clojure。参考状态的文档
ref function Usage: (ref x)
(ref x & options) Creates and returns a Ref with an initial value of x and zero or more options (in any order):
:meta metadata-map
:validator validate-fn
:min-history (default 0) :max-history (default 10)
If metadata-map is supplied, it will become the metadata on the ref.
validate-fn must be nil or a side-effect-free fn of one argument,
which will be passed the intended new state on any state change. If
the new state is unacceptable, the validate-fn should return false or
throw an exception. validate-fn will be called on transaction commit,
when all refs have their final values.
Normally refs accumulate history dynamically as needed to deal with
read demands. If you know in advance you will need history you can set
:min-history to ensure it will be available when first needed (instead
of after a read fault). History is limited, and the limit can be set
with :max-history. Added in Clojure version 1.0
您一开始的两个关键字看起来像是在尝试为参考定义元数据。您需要在定义 ref 时使用 :meta 选项(这是我对您的真实意图的猜测,可能完全不正确)。
ref 的强制参数是初始值。这需要是一个有效的 clojure 'structure' 或一个 returns 函数。就您而言,您看起来想要一张地图。
我认为您不需要嵌套引用。虽然从技术上讲,我认为您可以定义它们,但这几乎肯定不是您真正想要的。阅读 refs and transactions 以了解您可能不想这样做的原因及其对执行 STM 的影响。一般的经验法则是隔离您需要确保管理的值。您需要细粒度的访问控制,并且希望避免嵌套访问控制,因为这会使事情变得过于复杂,并且您的访问控制将变得粗粒度。考虑您的银行账户操作。您不想在只对其中一个或两个帐户进行操作时锁定所有银行帐户 - 您只想 lock/control 更新所涉及的帐户。您可能想要的是 refs 的数组(向量)或者可能是普通的 hash-map,其中一个键是帐户,值是 ref,而 ref 又是一个映射,其中包含您需要确保的值在事务中更新(其他选项将包括信号量或临界区方法,其中 ref 是一个简单的 flag/lock,它确定事务是否可以继续或必须回绕并再次尝试。
我想您可能需要多考虑一下您的数据结构。尝试一下散列映射并尝试嵌套结构。在这些基本和嵌套数据结构(map、filter、reduce、loop/recur、sequences 和 laziness 等)上使用核心函数。获得正确的基本抽象,然后查看需要如何更改它以确保一致性在您的数据中,即如何确保您的交易具有适当的原子性,尤其是当涉及多个帐户时。您当前的嵌套结构无效 - 例如,查看 :operations 值。那是什么值?它是交易引用的向量? clojure 如何知道这是一个向量?您的应用程序需要如何提取该数据?最频繁的操作是什么——一起提取还是提取单个交易?它们需要按日期顺序排列吗?这有多容易获得特定日期的交易?一旦您拥有数百个账户和数千笔交易,这种规模会扩大吗?等等。正确抽象,容易的事情仍然很容易。弄错了,容易的事情会很困难,而且困难的事情可能会更难。
我正在与 refs 打交道,我需要一些帮助。
我这里有 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"]}]
不需要相同,这只是一个想法,我正在尝试使用 map
和 deref
,但仍然卡住了。
您的代码有很多问题需要解决。虽然 clojure 对 parallelism/concurrency 有很好的支持,但您需要先掌握正确的基础知识。处理 activity 的多个线程是困难的,试图做到这一点的同时还要尝试弄清楚基本数据结构和核心函数的工作原理几乎是不可能的。
- 您的 ref 函数不是有效的 clojure。参考状态的文档
ref function Usage: (ref x) (ref x & options) Creates and returns a Ref with an initial value of x and zero or more options (in any order):
:meta metadata-map
:validator validate-fn
:min-history (default 0) :max-history (default 10)
If metadata-map is supplied, it will become the metadata on the ref. validate-fn must be nil or a side-effect-free fn of one argument, which will be passed the intended new state on any state change. If the new state is unacceptable, the validate-fn should return false or throw an exception. validate-fn will be called on transaction commit, when all refs have their final values.
Normally refs accumulate history dynamically as needed to deal with read demands. If you know in advance you will need history you can set :min-history to ensure it will be available when first needed (instead of after a read fault). History is limited, and the limit can be set with :max-history. Added in Clojure version 1.0
您一开始的两个关键字看起来像是在尝试为参考定义元数据。您需要在定义 ref 时使用 :meta 选项(这是我对您的真实意图的猜测,可能完全不正确)。
ref 的强制参数是初始值。这需要是一个有效的 clojure 'structure' 或一个 returns 函数。就您而言,您看起来想要一张地图。
我认为您不需要嵌套引用。虽然从技术上讲,我认为您可以定义它们,但这几乎肯定不是您真正想要的。阅读 refs and transactions 以了解您可能不想这样做的原因及其对执行 STM 的影响。一般的经验法则是隔离您需要确保管理的值。您需要细粒度的访问控制,并且希望避免嵌套访问控制,因为这会使事情变得过于复杂,并且您的访问控制将变得粗粒度。考虑您的银行账户操作。您不想在只对其中一个或两个帐户进行操作时锁定所有银行帐户 - 您只想 lock/control 更新所涉及的帐户。您可能想要的是 refs 的数组(向量)或者可能是普通的 hash-map,其中一个键是帐户,值是 ref,而 ref 又是一个映射,其中包含您需要确保的值在事务中更新(其他选项将包括信号量或临界区方法,其中 ref 是一个简单的 flag/lock,它确定事务是否可以继续或必须回绕并再次尝试。
我想您可能需要多考虑一下您的数据结构。尝试一下散列映射并尝试嵌套结构。在这些基本和嵌套数据结构(map、filter、reduce、loop/recur、sequences 和 laziness 等)上使用核心函数。获得正确的基本抽象,然后查看需要如何更改它以确保一致性在您的数据中,即如何确保您的交易具有适当的原子性,尤其是当涉及多个帐户时。您当前的嵌套结构无效 - 例如,查看 :operations 值。那是什么值?它是交易引用的向量? clojure 如何知道这是一个向量?您的应用程序需要如何提取该数据?最频繁的操作是什么——一起提取还是提取单个交易?它们需要按日期顺序排列吗?这有多容易获得特定日期的交易?一旦您拥有数百个账户和数千笔交易,这种规模会扩大吗?等等。正确抽象,容易的事情仍然很容易。弄错了,容易的事情会很困难,而且困难的事情可能会更难。