Вопрос

Мне нужно определить взаимозависимые VAR. Под этим я имею в виду, что один 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

Надеюсь, это поможет, хотя я не вижу, как это будет полезно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top