Clojure中有一种聪明的方法来验证函数输入吗?

9
我正在编写一个简单的 DiceRoller 应用程序,并创建了主要函数。然而,我想知道是否有一种“智能”方式在 Clojure 中验证函数输入,而不是使用分支条件来验证输入?我的函数如下所示,附带一个样本测试。我还需要测试 n 是否不是数字,使用另一个 if 或 or 进行测试,这感觉很混乱。
如果有人能指出更聪明的方法来执行此函数,我将非常感激任何反馈。这是我第一次尝试编写函数式程序。
(ns DiceRoller)

(defn roll
"rolls a specified number of n sided dice "
([] (roll 1 6))
([number] (roll number 6))
([number n]
  (if-not number? number (throw (IllegalArgumentException. (str "incorrect input, integers only"))))
  (take number (repeatedly #(+ (rand-int n) 1)))
  )
)
2个回答

25

当然有办法的 - 你可以使用 :pre 断言来实现。

(defn some-fun [x]
  {:pre [(number? x)]}
  (foo x))

现在,如果您将一个非数字参数x传递给函数,您将得到AssertionError Assert failed: (number? x)

正如@amalloy已经指出的那样,检查输入是否为数字有点无用,但您可能希望对您的函数应用许多完全有效的先决条件(以及后置条件)。您可以在此处了解更多详情这里


我喜欢这个,但是在调用函数时需要使用 try-catch 不是有点“恶心”吗?感觉太像 Java 了。 - Matthew H

7
大多数Clojure开发者的态度是“假设你拥有了正确的东西”。在这种情况下,如果你完全删除了你的检查,用户最终会得到基本相同的异常。但是,如果你真的想这么做,你应该正确地操作!现在你的代码对每个输入都抛出一个异常,因为你错过了(number? number)周围的括号。

谢谢,我只是举了一个例子来发布这个帖子,没有进行任何调试。我本来以为优雅地失败会更好,闭包是否具有内置的catch块功能? - LiamRyan
2
repeatedly注意到number不是数字时,抛出自定义异常比抛出“自动”异常更加优雅,你觉得呢? - amalloy
2
@amalloy,这给了你一个机会提供更有意义的错误信息。这对用户来说比期望他们反复解码任何异常要好得多。 - mikera
“只是假设您得到了正确的东西”与防御式编程的概念相反。 - marathon
不考虑态度,这里的另一个答案展示了执行输入验证的惯用方式,而且在许多情况下这是有用的。 - matanster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接