我在Clojure中有一组数字函数,我想验证参数.函数期望有许多类型的参数,例如正整数,百分比,数字序列,非零数字序列等.我可以通过以下方式验证任何单个函数的参数:
将验证代码写入函数.
编写通用函数,将参数和期望类型传递给它.
编写通用宏,将参数和期望类型传递给它.
其他我没有想到的.
Larry Hunter的一些Lisp代码是#3的一个很好的例子.(寻找test-variables
宏.)
我的直觉是宏更合适,因为对评估的控制和编译时计算的潜力,而不是在运行时完成所有操作.但是,我没有遇到我正在编写的代码似乎需要它的用例.我想知道编写这样一个宏是否值得付出努力.
有什么建议?
Clojure已经(没有文档记录,可能会有更改)支持fn
s的前后条件.
user> (defn divide [x y] {:pre [(not= y 0)]} (/ x y)) user> (divide 1 0) Assert failed: (not= y 0) [Thrown class java.lang.Exception]
虽然有点难看.
我可能会编写一个宏,这样我就能以简洁的方式报告哪些测试失败了(引用并按字面打印测试).您链接到的CL代码看起来非常讨厌这个巨大的案例陈述.在我看来,Multimethods在这里会更好.你可以很容易地把这样的东西扔到一起.
(defmacro assert* [val test] `(let [result# ~test] ;; SO`s syntax-highlighting is terrible (when (not result#) (throw (Exception. (str "Test failed: " (quote ~test) " for " (quote ~val) " = " ~val)))))) (defmulti validate* (fn [val test] test)) (defmethod validate* :non-zero [x _] (assert* x (not= x 0))) (defmethod validate* :even [x _] (assert* x (even? x))) (defn validate [& tests] (doseq [test tests] (apply validate* test))) (defn divide [x y] (validate [y :non-zero] [x :even]) (/ x y))
然后:
user> (divide 1 0) ; Evaluation aborted. ; Test failed: (not= x 0) for x = 0 ; [Thrown class java.lang.Exception] user> (divide 5 1) ; Evaluation aborted. ; Test failed: (even? x) for x = 5 ; [Thrown class java.lang.Exception] user> (divide 6 2) 3