Константы времени компиляции Clojure

Этот вопрос исходит исключительно из «умственной мастербации» и, вероятно, не имеет практической ценности.

Если я определяю значение в Clojure, используя def, можно ли заставить компилятор оценивать его во время компиляции, а не ждать до времени выполнения?

(def the-answer 42)

(+ the-answer 1)

Думаю, я мог бы определить макрос, но синтаксис вызова становится несколько неудобным:

(defmacro the-answer [] 42)

(+ (the-answer) 1)

Это также работает, но все еще уродливо:

(+ `~the-answer 1)

Я также понимаю (или верю), что Clojure оценивает константные выражения во время компиляции:

(def milliseconds-per-day (* 24 60 60 1000))

Я только изучаю Common Lisp, но насколько я понимаю, Common Lisp поддерживает определяемые пользователем макросы чтения, поэтому вы можете определить макрос чтения (что-то вроде #$), который оценивает следующий символ во время компиляции:

(+ #$the-answer 1)

Между прочим, этот синтаксис ничуть не "красивее", чем вызов макроса.

Как заставить Clojure оценивать постоянные переменные во время компиляции и заменять ссылку фактическим значением? Это уже так?

Прежде чем кто-нибудь начнет цитировать закон Кнута («преждевременная оптимизация — корень всех зол»), я задаю этот вопрос, чтобы лучше понять внутренности компиляции Clojure.


person Ralph    schedule 10.11.2011    source источник
comment
Это не то, что является понтификацией. Понтификация – это говорить напыщенно или догматически.   -  person Adrian Mouat    schedule 10.11.2011


Ответы (3)


Из документов по Clojure 1.3

== 2.14 ^:постоянные определения ==

^:const позволяет вам именовать примитивные значения с более быстрой ссылкой.

(константы определения {:pi 3.14:e 2.71})

(def ^:const pi (:pi константы)) (def ^:const e (:e константы))

Накладные расходы на поиск :e и :pi на карте возникают во время компиляции, поскольку (:pi константы) и (:e константы) оцениваются, когда оцениваются их родительские формы определения.

person Julien Chastang    schedule 10.11.2011

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

person Arthur Ulfeldt    schedule 10.11.2011
comment
Это разумный ответ, и я думал о том же. Синтаксис лучше, чем альтернатива `~the-answer. - person Ralph; 10.11.2011

`~foo буквально идентичен foo во всех случаях - что бы вы ни думали, что получаете от первого, это иллюзия.

Я думаю, что :const, вероятно, правильный ответ, но вы также можете использовать символьные макросы из clojure.tools.macro — для этой цели (а также для других целей) у него есть symbol-macrolet и defsymbolmacro/with-symbol-macros.

person amalloy    schedule 14.11.2011
comment
Я не понимал, что ~foo. Thanks. As I think more about the problem, the ^:const` кажется правильным, но только для примитивов (не включая экземпляры String). Проблема со строками заключается в том, что использование макроса или константы, вероятно, приведет к сравнению во время выполнения содержимого String, а не адресов. Если причина сделать это для производительности, это потеря. - person Ralph; 14.11.2011