定义相互依赖的变量

时间:2012-02-17 05:14:37

标签: variables clojure mutual-recursion

我需要定义相互依赖的变量。我的意思是,一个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
显然,那不是它应该如何运作。 我知道打印这样的结构会给堆栈溢出,但我不需要打印它。我该怎么办?

3 个答案:

答案 0 :(得分:3)

您可以执行以下操作:

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

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

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

我仍然不太确定你为什么要这样做尽管.....试图让vars相互依赖,这对我来说似乎是一个非常糟糕的代码味道。无论你想要做什么,实际上最好通过不同的方法来解决。

修改

由于额外的评论声明问题与不同类型的实体相互引用有关,我认为更好的方法是使用关键字的地图,例如。

(def my-model
  {:a 
      {:name "Entity A" 
       :references [:b]}
   :b 
      {:name "Entity B"
       :references [:a]}}

答案 1 :(得分: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]

答案 2 :(得分: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

希望它有所帮助,虽然我看不出它会如何有用。