3

この関数では:

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

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

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

実際、これは正しく機能します。

問題は、これが黙って失敗したことであり、何が問題なのかを理解するのにしばらく時間がかかりました. 構文エラー、実行時例外はありません。

Clojure が文句を言わなかった理由を理解するために、Clojure がこのコードで何をするのかを理解したいと思います。 マクロ展開?破壊?角括弧が表示されない場合、コードは消えますか?

4

1 に答える 1

5

http://clojure.org/special_formsfnは、 (したがって も)の条件マップdefnが次の形式である必要があることを文書化しています。

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

{:post (number? %)}(number? %)一連のアサーションとして扱われます。つまり、2 つの別個のアサーションとして解釈されます: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?が定義されていて真の値を持っている 限り、常に通過します。これはコア関数であるため、おそらく通過します。値が true の(clojure.core/assert %)場合に合格します。を介して%引数の値にバインドされているため、真の値がある場合に合格します。最初の関数定義で呼び出してみると、アサーションに失敗します。aleta(my-post nil)

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? %))
   %)))
于 2011-10-27T19:01:56.130 に答える