3

在這個函數中:由於語法錯誤,Clojure後置條件無法執行 - 爲什麼?

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

的後置條件不執行(或至少,不引起斷言錯誤)。我現在知道它應該是:

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

事實上,它的確能正常工作。

問題是,這失敗了,我花了一段時間找出錯誤。沒有語法錯誤,運行時異常。

我想了解Clojure用這段代碼做什麼,以瞭解Clojure爲什麼沒有抱怨。宏擴展?解構?如果代碼沒有看到方括號,代碼是否會消失?

+0

請解釋一下什麼是這個職位的條件?我無法弄清楚這是什麼方法的目的。 –

回答

5

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 %)。它通過let綁定到a的參數值,所以如果a具有真值,則它通過。嘗試使用您的第一個函數定義調用(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? %)) 
    %)))