Как изменить :arglists на Clojure fn или макрос?

Как изменить атрибут :arglist для clojure fn или макроса?

(defn tripler ^{:arglists ([b])} [a] (* 3 a))

(defn ^{:arglists ([b])} quadrupler [a] (* 4 a))

% (meta #'tripler) => 
  {:arglists ([a]), :ns #<Namespace silly.testing>, :name tripler, :line 1, :file "NO_SOURCE_PATH"}

% (meta #'quadrupler) => 
  {:arglists ([a]), :ns #<Namespace silly.testing>, :name quadrupler, :line 1, :file "NO_SOURCE_PATH"}

Хорошо, не повезло, поэтому я попытался сделать следующее.

(def tripler
  (with-meta trippler
    (assoc (meta #'tripler) :arglists '([c]))))

% (with-meta #'tripler) => 
  {:ns #<Namespace silly.testing>, :name tripler, :line 1, :file "NO_SOURCE_PATH"}

Хм, так теперь ключ :arglists пропал? Ну, я сдаюсь, как мне это сделать? Я просто хотел бы изменить значение :arglists. В приведенных выше примерах используется defn, но я также хотел бы знать, как установить :arglists с помощью макроса (defmacro).


person Stephen Cagle    schedule 20.09.2012    source источник


Ответы (4)


alter-meta! изменяет метаданные переменной var. Метаданные функции не имеют значения, только var.

(alter-meta! #'tripler assoc :arglists '([b]))
person amalloy    schedule 20.09.2012
comment
Хотя это правда, defn позволяет вам указать карту атрибутов, что является более чистым способом сделать то, что хочет Стивен. Смотрите мой ответ ниже. - person duelin markers; 02.11.2012

Вам не нужно делать ничего столь же уродливого, как предложения до сих пор. Если вы посмотрите на собственные arglists defn*...

user=> (:arglists (meta #'clojure.core/defn))
([name doc-string? attr-map? [params*] prepost-map? body]
 [name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?])

Вы ищетеattr-map. Вот пример.

user=> (defn foo
         "does many great things"
         {:arglists '([a b c] [d e f g])}
         [arg] arg)
#'user/foo
user=> (doc foo)
-------------------------
user/foo
([a b c] [d e f g])
  does many great things
nil

В этом случае arglists — полная ложь. Не делай этого!

*Обратите внимание, что я использовал clojure.core/defn, а не просто defn. Это имеет значение, и я не знаю, почему. Так же и с doc.

person duelin markers    schedule 01.11.2012
comment
Для будущих искателей этого вопроса: это правильный ответ, остальные - обходные пути или совершенно неверны. - person whereswalden; 26.02.2021

defn не оставляет места для искажения метаданных, что нормально, потому что это просто макрос, обертывающий def. Вы можете использовать def напрямую вместо defn:

core> (def  ^{:arglists '([b])} tripler (fn [a] (* 3 a)))
#'core/tripler                                                                                 
core> (meta #'tripler)
{:arglists ([b]), :ns #<Namespace autotestbed.core>, :name tripler, :line 1, :file "NO_SOURCE_FILE"}

или вы определяете тройник var с помощью defn:

core> (defn tripler [a] (* 3 a))
#'autotestbed.core/tripler                                                               

затем переопределите переменную с тем же содержимым и другими метаданными:

core> (def ^{:arglists '([b])} tripler  tripler)
#'autotestbed.core/tripler                                                                                 
autotestbed.core> (meta #'tripler)
{:arglists ([b]), :ns #<Namespace autotestbed.core>, :name tripler, :line 1, :file "NO_SOURCE_FILE"}
person Arthur Ulfeldt    schedule 20.09.2012

Расширение ответа амаллоя (пожалуйста, отдайте ему должное):

user=> (defn foo "prints bar" [] (println "bar"))
#'user/foo

user=> (doc foo)
-------------------------
user/foo
([])
  prints bar
nil

user=> (meta #'foo)
{:arglists ([]), :ns #<Namespace user>, :name foo, :doc "prints bar", :line 1, :file "NO_SOURCE_PATH"}

user=> (alter-meta! #'foo assoc :arglists '([blah]))
{:arglists ([blah]), :ns #<Namespace user>, :name foo, :doc "prints bar", :line 1, :file "NO_SOURCE_PATH"}

user=> (doc foo)
-------------------------
user/foo
([blah])
  prints bar
nil

user=> (meta #'foo)
{:arglists ([blah]), :ns #<Namespace user>, :name foo, :doc "prints bar", :line 1, :file "NO_SOURCE_PATH"}

user=> (foo)
bar
nil

Подлый!

person noahlz    schedule 20.09.2012