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

时间:2011-10-27 13:42:04

标签: compilation clojure compiler-errors compiler-warnings post-conditions

在此功能中:

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

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

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

事实上,哪种方法可以正常工作。

问题在于,这种方式无声无息,并花了一些时间来弄清楚出了什么问题。没有语法错误,运行时异常。

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

1 个答案:

答案 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 %)具有真值,则会%通过。它通过a与您的参数let的值绑定,因此如果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? %))
   %)))