Clojure карет как символ?

Поэтому я подумал, что было бы неплохо назвать функцию, которая вычисляет экспоненту ^, но похоже, что каретка действительно делает что-то особенное, так как Clojure REPL генерирует ошибку при оценке '^. Googling в основном дал мне это, так что мне было интересно, что фактическое использование для каретки в Clojure.

(Кроме того, было бы возможно в конце концов назвать функцию ^?)

Ответ 1

^ является "метасимволом", он говорит читателю добавить символ, начинающийся с ^ как метаданные, к следующему символу (если это то, что реализует IMetas)

user=> (def x ^:IamMeta [1 2 3])
#'user/x
user=> x
[1 2 3]
user=> (meta x)
{:tag :IamMeta}
user=> 

Вы можете много узнать о том, как clojure работает под капотом, глядя на meta -вещи, например функции:

user=> (meta foo)                          
{:ns #<Namespace user>, 
 :name foo, :file "NO_SOURCE_PATH", 
 :line 5, :arglists ([s])}

это очень часто используется для подсказок типа

(defn foo [^String s] (.charAt s 1))

обычно рекомендуется включать предупреждения отражения (set! *warn-on-reflection* true) а затем добавлять подсказки типа до тех пор, пока предупреждения не исчезнут. без этих Clojure будет искать тип функциональных операндов во время выполнения, что избавит вас от проблем с типами, хотя и с небольшими затратами.

PS: Мой следующий любимый персонаж читателя - это символ "отправки" #, он стоит узнать об этом дальше :)

PPS: это отличается от clojure 1.2.x vs clojure 1.3.x в Clojure 1.2.1 метаданные не создаются, когда вы используете метасимвол:

user=> (def foo ^:foo ^:bar [1 2 3])
#'user/foo
user=> (meta foo)
{:tag :foo}

и в 1.3 он "делает правильную вещь", а также ключевые слова - это опции вместо "тегов":

user=> (def foo ^:foo ^:bar [1 2 3])
#'user/foo
user=> (meta foo)
{:foo true, :bar true}

Ответ 2

Мне кажется, что ответ на ваш вопрос, к сожалению, нет. В Clojure вы не можете назвать функцию ^.

Я пробовал в REPL:

user=> (println \^)
^
nil

Это, по-видимому, означает, что вы можете избежать карат (^) с обратной косой чертой. Однако, если я попытаюсь объявить функцию, используя \^ как имя, тогда я получаю сообщение об ошибке:

user=> (defn \^ [n e] (cond (= e 0) 1 :else (* n (\^ n (- e 1)))))
IllegalArgumentException First argument to defn must be a symbol
clojure.core/defn (core.clj:277)

Тот же код работает с обычным текстовым именем:

user=> (defn exp [n e] (cond (= e 0) 1 :else (* n (exp n (- e 1)))))
#'user/exp
user=> (exp 3 3)
27

Я был бы рад, если бы кто-то с лучшим Clojure-fu, чем мой, мог доказать мне ошибку! :)