構文エラーのためClojureのpost-conditionが実行されない - なぜですか?

この関数では:

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

事後条件は実行されません(少なくとも、アサーションエラーは発生しません)。私は今それがあったはずであることを知っている:

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

実際に正しく動作します。

問題は、これが黙って失敗し、何が間違っていたかを理解するためにしばらく時間がかかりました。構文エラー、ランタイム例外はありません。

I would like to understand what Clojure does with this code, in order to understand why Clojure didn't complain. Macro expansions? Destructuring? Does the code just disappear if it doesn't see square braces?

3
追加された
ビュー: 2
この後の状態は何ですか?私はこの方法の目的が何であるか把握することができません。
追加された 著者 Abimaran Kugathasan,

1 答え

http://clojure.org/special_forms documents that the condition-map for fn (thus also defn) should be of the form:

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

{:post (number? %)} will result in (number? %) being treated as a sequence of assertions, which means it's interpreted as two separate assertions: number? and %.

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

(assert number?) always passes as long as number? is defined and has a true value, which being a core function, it probably does. (clojure.core/assert %) passes if % has a true value. It's bound to the value of your argument a via the let, so it passes if a has a true value. Try calling (my-post nil) with your first function definition and it'll fail the assertion.

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

事後条件をベクトルに適切に入れると、次のように展開されます。

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