A nyelv biztosít eszközöket a programok helyességének futásidejű ellenőrzésére is az elő- és utófeltételek nyelvi, illetve runtime szinten történő bevezetésével.
A függvényekhez kapcsolt metaadatok révén lehetőség nyílik a nyelvben elő- és utófeltételek futásidejű ellenőriztetésére is:
user=> (defn negyzet [x] {:pre [(> x 10)] :post [(< % 2200)]} (* x x)) #'user/negyzet user=> (negyzet 1000) java.lang.AssertionError: Assert failed: (< % 2200) (NO_SOURCE_FILE:0) user=> (negyzet 2) java.lang.AssertionError: Assert failed: (> x 10) (NO_SOURCE_FILE:0)
Az elő- utófeltételeket paraméterként is beinjektálhatjuk a függvénybe:
user=> (defn check ([pre f post] {:pre [pre] :post [post]} f) ([pre f x post] {:pre [pre] :post [post]} (f x))) user=> (check (> x 10) negyzet #(< % 2200)) ; ha nem adunk át neki paramétert, egy ellenőrzéssel ellátott f-fel tér vissza #<user$negyzet user$negyzet@107d6ae> user=> ( (check (> x 10) negyzet #(< % 2200)) 1000) ; amit meghívhatunk.... java.lang.AssertionError: Assert failed: (< % 2200) (NO_SOURCE_FILE:0) user=> (check (> x 10) negyzet 12000 #(< % 2200)) ; ha paramétert is adunk a check-nek, végrehajtja a függvényt, elő/utófeltétel ellenőrzéssel java.lang.AssertionError: Assert failed: (< % 2200) (NO_SOURCE_FILE:0)
Makrók segítségével különböző ciklus-"invariánsok" futásidejű ellenőrzését végző szerkezeteket is írhatunk. Írjunk egy olyan ciklust, ami minden iteráció elején ellenőriz egy, a ciklusban megadott logikai állítást!
(defn index-filter "Megszuri a sorozatot az elem indexenek predikatuma alapjan" [pred coll] (for [i (range (count coll)), :when (pred i)] (get coll i))) (defn odd-indexes "Visszaadja egy lista paratlan elemeit: elsot, harmadikat, otodiket, stb." [coll] (index-filter (comp odd? inc) coll)) (defn even-indexes "Visszaadja egy lista paros elemeit: masodikat, negyediket, hatodikat, stb." [coll] (index-filter (comp even? inc) coll)) (defmacro loopin [bindings _ inv body] `(letfn [(loop_fn# ~(vec (odd-indexes bindings)) {:pre ~inv} ~body)] (loop_fn# ~@(even-indexes bindings))))
A loopin (invariánssal kibővített loop) makró használatát a következő példán is láthatjuk:
(defn lnko[x y] "Visszaadja a ket parameter legnagyobb kozos osztojat" (loopin [a x b y] :invariant [(number? a) (number? b)] (if (= b 0) a (recur b (mod a b)))))
Látható, hogy az lnko minden iterációjában ellenőrizzük, hogy a két paraméter típusa valóban szám-e, és ha az egyik állítás nem teljesül, hibát kapunk:
user=> (lnko 24 36) 12 user=> (lnko 24 "36") java.lang.AssertionError: Assert failed: (number? b) (NO_SOURCE_FILE:0)