定义相互依赖的变量



我需要定义相互依赖的变量。我的意思是,一个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

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

您可以执行以下操作:

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

注意,#'是一个用于引用变量的读取器宏

我仍然不太确定你为什么要这么做。。。。。在我看来,试图让vars相互依赖似乎是一种很糟糕的代码气味。很可能,无论你想做什么,都最好用不同的方法来解决。

编辑

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

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

首先,这闻起来很像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]

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

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

希望它能有所帮助,尽管我看不出它会有什么用处。

最新更新