Clojure-postconditie kan niet worden uitgevoerd vanwege syntaxisfout - waarom?

In deze functie:

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

De postconditie wordt niet uitgevoerd (of veroorzaakt in ieder geval geen assertiefout). Ik weet nu dat het had moeten zijn:

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

Dat werkt in feite correct.

Het probleem is dat dit in stilte faalde en het kostte me een tijdje om erachter te komen wat er mis was. Geen syntaxisfouten, runtime-uitzonderingen.

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
Leg uit wat deze berichtentoestand is? Ik kan niet achterhalen wat dit doel van de methode is.
toegevoegd de auteur Abimaran Kugathasan, de bron

1 antwoord

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]

Als u uw postconditie correct in een vector hebt geplaatst, wordt deze zo uitgebreid:

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