Постусловие Clojure не выполняется из-за синтаксической ошибки - почему? - PullRequest
3 голосов
/ 27 октября 2011

В этой функции:

(defn my-post 
  [a] 
  {:post (number? %)}
  a)

Постусловие не выполняется (или, по крайней мере, не вызывает ошибку утверждения). Теперь я знаю, что это должно было быть:

(defn my-post 
  [a] 
  {:post [(number? %)]} ;; note the square brackets around the expression
  a)

Что, на самом деле, работает правильно.

Проблема в том, что это молча провалилось, и мне потребовалось время, чтобы выяснить, в чем дело. Нет синтаксических ошибок, исключения времени выполнения.

Я хотел бы понять, что Clojure делает с этим кодом, чтобы понять, почему Clojure не жаловался. Расширения макросов? Уничтожение того? Код просто исчезает, если он не видит квадратных скобок?

1 Ответ

5 голосов
/ 27 октября 2011

http://clojure.org/special_forms документирует, что карта условий для fn (таким образом также defn) должна иметь форму:

{:pre [pre-expr*]
 :post [post-expr*]}

{:post (number? %)} приведет к (number? %)рассматривается как последовательность утверждений, что означает, что оно интерпретируется как два отдельных утверждения: number? и %.

user> (macroexpand-1 '(fn [a] {:post (number? %)} a))
(fn*
 ([a]
  (clojure.core/let [% a]
   (clojure.core/assert number?)
   (clojure.core/assert %)
   %)))

(assert number?) всегда проходит, пока number? определено и имеетистинное значение, которое является основной функцией, вероятно, так и есть.(clojure.core/assert %) проходит, если % имеет истинное значение.Он связан со значением вашего аргумента a через let, поэтому он проходит, если a имеет истинное значение.Попробуйте вызвать (my-post nil) с вашим первым определением функции, и оно не будет подтверждено.

user> (my-post nil)
; Evaluation aborted.
; Assert failed: %
;  [Thrown class java.lang.AssertionError]

Если вы правильно поместите свое постусловие в вектор, оно расширится так:

...