문제

I need to define mutually-dependent vars. By this I mean that one var contains e.g. a vector with another var and vice versa. This is illustrated by the following code:

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

But after loading this code I get this:

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

clearly, thats not how it should work. I understand that printing such structure will give stack overflow, but I don't need to print it. How should I do it?

도움이 되었습니까?

해결책

You can do the following:

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

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

Note that #' is a reader macro for referring to a var.

I'm still not quite sure why you want to do this though..... trying to make vars mutually dependent like this seems like a pretty bad code smell to me. It's likely that whatever you are trying to do would actually be best solved by a different approach.

EDIT

With the extra comment stating that the problem is related to having different types of entities referring to each other, I think a better approach is a map with keywords, e.g.

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

다른 팁

First, this smells very much like an XY problem.

Second, mutually referential data structures cannot be created without mutating state. If that's the data structure you need (and you probably don't), then use clojure's very well designed approach to state. For example:

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]

Lazy evaluation might help:

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

Hope it helps, though I can't see how it's going to be useful.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top