Как сделать Clojure уважать `* assert *` переменную?

Мне нужно было понять, что переменная Clojure *assert* может использоваться для отключения утверждений, но ничего не работает.

(defn foo [a]
  {:pre [(pos? a)]}
  (assert (even? a))
  [a])

(binding [*assert* false]
  (foo 1))
!! exception

(binding [*assert* false]
  (foo -2))
!! exception

Даже при привязке false, когда определение имеет такие же проблемы:

(binding [*assert* false]
  (defn bar [a]
    {:pre [(pos? a)]}
    (assert (even? a))
    [a]))

(bar 1)
!! execption

И тогда даже установка переменной direct не работает.

*assert*
is true

(alter-var-root (var *assert*) not)
*assert*
is still true

и

(var-set (var *assert*) false)
*assert*
is still true

Итак, теперь я не понимаю, что делать. Я смущен.

Спасибо.

Ответ 1

*assert* - это переменная времени компиляции, а не переменная времени выполнения. Он должен использоваться с set! как оператор верхнего уровня, а не с привязкой (конечно, если вы не вызываете eval внутри привязки).

Ответ 2

assert - это макрос, определенный таким образом, что * assert * влияет на его поведение во время расширения.

если вы попробуете этот код, он будет работать как ожидалось:

(binding [*assert* false]
   (eval '(assert false))
)

и ваш пример с var-set также должен работать:

(var-set (var *assert*) false)
(assert false)