Измените значение параметра Clojure var, не касаясь метаданных

#clojure #metadata

Вопрос:

Я работал над предположением, что метаданные var «стабильны», то есть я могу изменить значение var, не изменяя метаданные var. Теперь я вижу, что с моим пониманием что-то не так. Код:

 (def ^{:Metadata "metaA"} A 1)  ;; Define A with value 1 and metadata.
=> #'thic.core/A
(def ^{:Metadata "metaB"} B 2)  ;; Define B with value 2 and metadata.
=> #'thic.core/B
A                               ;; A's value is 1.
=> 1
B                               ;; B's value is 2.
=> 2
(meta (var A))
=>
{:Metadata "metaA",             ;; A has the defined metadata.
 :line 1,
 :column 1,
 :file "C:\Users\Joe User\AppData\Local\Temp\form-init2487748963910096550.clj",
 :name A,
 :ns #object[clojure.lang.Namespace 0x147c445 "thic.core"]}
(meta (var B))
=>
{:Metadata "metaB",             ;; So does B.
 :line 1,
 :column 1,
 :file "C:\Users\Joe User\AppData\Local\Temp\form-init2487748963910096550.clj",
 :name B,
 :ns #object[clojure.lang.Namespace 0x147c445 "thic.core"]}
(def B A)                       ;; Give B A's value,
=> #'thic.core/B
A
=> 1
B                               ;; which it now has,
=> 1
(meta (var B))                  ;; and B's previously-defined metadata is gone.
=>
{:line 1,
 :column 1,
 :file "C:\Users\Joe User\AppData\Local\Temp\form-init2487748963910096550.clj",
 :name B,
 :ns #object[clojure.lang.Namespace 0x147c445 "thic.core"]}
(meta (var A))                  ;; A's remains unchanged.
=>
{:Metadata "metaA",
 :line 1,
 :column 1,
 :file "C:\Users\Joe User\AppData\Local\Temp\form-init2487748963910096550.clj",
 :name A,
 :ns #object[clojure.lang.Namespace 0x147c445 "thic.core"]}
 

Есть ли способ присвоить значение A B без удаления метаданных в B?
Или, может быть, я просто не понимаю разницы между «привязкой» и «назначением»?
В Clojure в действии 2-го издания говорится: «Когда создаются новые значения из тех, которые имеют метаданные, метаданные копируются в новые данные». (стр. 57) Мой пример не создает новое значение. В этом ли проблема? Я все еще хочу изменить значение var без изменения его метаданных.
Я смиренно умоляю тебя, ClojureGods.

Комментарии:

1. не могли бы вы, пожалуйста, пояснить, почему вам нужно переопределить var с def помощью . Каков вариант использования?. Это действительно выглядит однообразно в clojure. Хотя alter-var-root бы сделал это, все же, возможно, есть лучший способ реализовать желаемую функциональность.

2. литвински: Я не женат на «def», чтобы изменять значение var, если есть какой-либо другой способ сделать это, который не изменяет метаданные. Это просто единственный способ, которым мои ограниченные знания о Clojure подсказывают мне, как это делается. Ваши предложения приветствуются, как и ваш интерес.

Ответ №1:

alter-var-root могу это сделать.

 -------------------------
clojure.core/alter-var-root
([v f amp; args])
  Atomically alters the root binding of var v by applying f to its
  current value plus any args
 

Напр.:

 ; Clojure 1.10.3
(def ^{:Metadata "metaA"} A 1)
; #'user/A
(def ^{:Metadata "metaB"} B 2)
; #'user/B
A
; 1
B
; 2
(meta #'A)
; {:Metadata "metaA", :line 1, :column 1, :file "NO_SOURCE_PATH", :name A, :ns #object[clojure.lang.Namespace 0x2189e7a7 "user"]}
(meta #'B)
; {:Metadata "metaB", :line 1, :column 1, :file "NO_SOURCE_PATH", :name B, :ns #object[clojure.lang.Namespace 0x2189e7a7 "user"]}
(alter-var-root #'B (constantly A))
; 1
B
; 1
(meta #'B)
; {:Metadata "metaB", :line 1, :column 1, :file "NO_SOURCE_PATH", :name B, :ns #object[clojure.lang.Namespace 0x2189e7a7 "user"]}
 

Комментарии:

1. Спасибо тебе, Кендрик. Имея 6 книг Clojure и только 2 упоминания об этом, очевидно, что я не должен изменять корневое значение var. Clojure-это «совершенно новый» вид языка программирования, к которому я, в конце концов, привыкну и в котором буду хорош.

2. @LionelGoulet Если вы видите это в дикой природе, скорее всего, это связано с «инструментами разработки». Например, некоторые user.clj из них предназначены для перезагрузки систем или действительно заменяют что-то для разработки или тестирования. Предполагая, что «позже» — это то, что вам нужно…