Clojure: Почему метаданные функции меняются, когда я повторно ввожу определение? - PullRequest
3 голосов
/ 10 декабря 2011

Вроде так:

java -cp clojure.jar clojure.main
Clojure 1.2.0
user=> (defn f [x] x)
#'user/f
user=> (meta f)
{:ns #<Namespace user>, :name f}
user=> (defn f [x] x)
#'user/f
user=> (meta f)
{:ns #<Namespace user>, :name f, :file "NO_SOURCE_PATH", :line 1, :arglists ([x])}
user=> 

Почему вызов meta не возвращает одно и то же значение каждый раз?

ОБНОВЛЕНИЕ: сыграв еще немного, я смог получить ответ на свой ближайший вопрос. defn макрос раскрывается в форму, которая добавляет (meta (var f) к f метаданным. И (meta (var f) включает дополнительную информацию, которой нет в (meta f), когда f определяется в первый раз. Итак, мой вопрос теперь таков: почему defn реализован так?

java -cp clojure.jar clojure.main
Clojure 1.2.0
user=> (defn f [x] x)
#'user/f
user=> (meta f)
{:ns #<Namespace user>, :name f}
user=> (meta (var f))
{:ns #<Namespace user>, :name f, :file "NO_SOURCE_PATH", :line 1, :arglists ([x])}
user=> (macroexpand '(defn f [x] x))
(def f (.withMeta (clojure.core/fn f ([x] x)) (.meta (var f)))) ; (.meta x) seems to be the same as (meta x)
user=> 

Ответы [ 2 ]

1 голос
/ 20 декабря 2011

Очевидно, что это поведение было более или менее «случайным» в Clojure 1.2 и было изменено в 1.3: http://groups.google.com/group/clojure/browse_thread/thread/964bba0ead8218ee/3ef0c841474c85f4?lnk=gst&q=function+meta+data#3ef0c841474c85f4

В 1.3 только мета содержит только Var - сама функция не назначеналюбые метаданные defn.

0 голосов
/ 10 декабря 2011

Clojure использует метаданные для хранения информации, откуда была прочитана функция, документы и т. Д. Переопределение функции может изменить это.


С http://clojure.org/metadata:

Важная вещь, которую нужно понимать в отношении метаданных, заключается в том, что они не считаются частью стоимости объекта. Таким образом, метаданные не влияют на равенство (или хэш-коды). Два объекта, которые отличаются только метаданными, равны.

Другой способ взглянуть на это - рассмотреть обратное: предположим, что Clojure не сбросил метаданные.

(defn fun []
  "docs for the original function"
  ...)

, а затем переопределить его:

(defn fun []
   ;; no doc string, different body
   ...)

Без сброса метаданных (doc fun) выдаст «документы для исходной функции».

Наконец, переопределение vars обычно выполняется во время разработки и обычно не при обычном выполнении программы. Поэтому имеет смысл полностью переопределить его, вместо того, чтобы идти в ногу с предыдущими определениями.

...