Как мне динамически находить метаданные для функции Clojure? - PullRequest
17 голосов
/ 08 апреля 2011

Скажем, у меня есть следующий код:

(defn ^{:graph-title "Function 1"} func-1
  [x]
  (do-something-with x))

(defn get-graph-title 
  [func]
  (str
    ((meta func) :graph-title))) 

Я ожидаю, что это вернет "функцию 1", но она вернет ноль.Я думаю, что это связано со следующим различием, которое я не понимаю полностью:

(meta func-1)
=>  {:ns some-ns-info, :name func-1}
(meta #'func-1)
=>  {:ns some-ns-info, :name func-1, :graph-title "Function 1"}

Может кто-нибудь объяснить мне это?

Ответы [ 3 ]

31 голосов
/ 08 апреля 2011

Метаданные для функции func-1, метаданные для Var #'func-1 и метаданные для символа 'func-1. Макрос читателя Clojure ^ добавляет метаданные к символу во время чтения. Макрос defn копирует метаданные из символа в Var во время компиляции.

До Clojure 1.2 функции не поддерживали метаданные. В Clojure 1.2 они делают это, и defn также копирует некоторые стандартные метаданные Var в функцию :

Clojure 1.2.0
user=> (defn ^{:foo :bar} func-1 [] nil) 
#'user/func-1
user=> (meta func-1)
{:ns #<Namespace user>, :name func-1}
user=> (meta #'func-1)
{:foo :bar, :ns #<Namespace user>, :name func-1, ...

Однако в текущих снимках Clojure 1.3 defn не копирует метаданные в функцию:

Clojure 1.3.0-master-SNAPSHOT
user=> (defn ^{:foo :bar} func-1 [] nil) 
#'user/func-1
user=> (meta func-1)
nil
user=> (meta #'func-1)
{:foo :bar, :ns #<Namespace user>, :name func-1, ...

В общем, если вы хотите получить метаданные определения, вы хотите метаданные в Var .

19 голосов
/ 08 апреля 2011

Метаданные присоединяются к var, а не к функции.

Таким образом, чтобы получить заголовок графика, вы должны получить запись :graph-title из мета var. Как тебе твои макросы?

(defmacro get-graph-title
  [func]
  `(:graph-title (meta (var ~func))))

(get-graph-title func-1)
=> "Function 1"
2 голосов
/ 08 апреля 2011

Метаданные, указанные вами в символе func-1 в вашем исходном коде, копируются в var с именем func-1 с помощью специальной формы def. См. Документацию для определения в http://clojure.org/special_forms

Когда вы оцениваете func-1, где это символ, связанный с переменной var, вы получаете значение переменной var (которая в данном случае является функциональным объектом). Смотри http://clojure.org/vars

Сам объект функции не получает автоматически метаданные, указанные вручную в символе / var.

Итак, информация, которую вы хотите, вообще отсутствует в функции. Он находится в переменной var, и вы должны указать, что вам действительно нужен сам var func-1 вместо его значения. Это то, что (var func-1), и эквивалентный ярлык # 'func-1 делает.

...