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)