由于语法错误,Clojure后置条件无法执行 - 为什么?

Mat*_*ick 3 compiler-errors compilation clojure compiler-warnings post-conditions

在这个功能:

(defn my-post 
  [a] 
  {:post (number? %)}
  a)
Run Code Online (Sandbox Code Playgroud)

后置条件不会执行(或至少不会导致断言错误).我现在知道应该是:

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

事实上,哪个工作正常.

问题是这种情况无声地失败了,并花了一些时间来弄清楚出了什么问题.没有语法错误,运行时异常.

我想了解Clojure对此代码的处理方式,以便了解为什么Clojure没有抱怨. 宏观扩张?解构?如果没有看到方括号,代码是否会消失?

Bri*_*per 5

http://clojure.org/special_forms文档中的条件映射fn(因此也是defn)应该是以下形式:

{:pre [pre-expr*]
 :post [post-expr*]}
Run Code Online (Sandbox Code Playgroud)

{: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 %)
   %)))
Run Code Online (Sandbox Code Playgroud)

(assert number?)总是在number?定义时传递,并且具有真值,这可能是核心功能. (clojure.core/assert %)如果%有真值则传递.它a通过the 绑定到你的参数的值let,所以如果它a有一个真值就传递它.尝试(my-post nil)使用您的第一个函数定义调用它将失败该断言.

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

如果您将后置条件正确地放在向量中,它会像这样扩展:

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