3

我需要定义相互依赖的变量。我的意思是一个var包含例如一个带有另一个var的向量,反之亦然。下面的代码说明了这一点:

(declare a b)
(def a [1 b])
(def b [a 2])

但是在加载此代码后,我得到了这个:

test=> (first a)
1
test=> (second a)
#<Unbound Unbound: #'test/b>
test=> (first b)
[1 #<Unbound Unbound: #'test/b>]
test=> (second b)
2

显然,这不是它应该如何工作的。我知道打印这样的结构会导致堆栈溢出,但我不需要打印它。我该怎么做?

4

3 回答 3

3

您可以执行以下操作:

(declare a b)
(def a [1 #'b])
(def b [#'a 2])

@(a 1)
=> [#'user/a 2]

请注意,这#'是一个用于引用 var 的读取器宏。

不过,我仍然不太确定您为什么要这样做……尝试使变量像这样相互依赖似乎对我来说是一种非常糟糕的代码气味。很可能无论您尝试做什么,实际上最好通过不同的方法来解决。

编辑

额外的评论指出问题与不同类型的实体相互引用有关,我认为更好的方法是带有关键字的地图,例如

(def my-model
  {:a 
      {:name "Entity A" 
       :references [:b]}
   :b 
      {:name "Entity B"
       :references [:a]}}
于 2012-02-17T06:52:04.957 回答
1

首先,这听起来很像 XY 问题。

其次,如果没有变异状态,就无法创建相互引用的数据结构。如果这是您需要的数据结构(您可能不需要),那么请使用 clojure 精心设计的状态方法。例如:

user=> (set! *print-level* 2)  ; this is necessary to stop the infinite print recursion
2
user=> (def a (atom [1]))
#'user/a
user=> (def b (atom [a 2]))
#'user/b
user=> (swap! a conj b)
[1 #<Atom@19ed00d1: #>]
user=> @a
[1 #<Atom@19ed00d1: #>]
user=> @b
[#<Atom@5c6c2308: #> 2]
于 2012-02-17T08:13:07.913 回答
0

惰性评估可能会有所帮助:

user=> (declare a b)
#'user/b
user=> (def a [1 (lazy-seq b)])
#'user/a
user=> (def b [(lazy-seq a) 2])
#'user/b
user=> (first a)
1
user=> (second b)
2
user=> (second a) ;stack overflow
user=> (first b) ;stack overflow
user=> (take 42 (second a)) ;still overflow as it's infinitely deep
user=> (take 42 (first b)) ;still overflow as it's infinitely deep

希望它有所帮助,虽然我看不出它会有什么用处。

于 2012-02-21T00:43:15.547 回答