对 clojure 中的函数参数施加限制

Imposing restrictions on function args in clojure

我经常发现自己在做这样的事情:

(defn f1 [coll]
  (if (not= (count coll) 2)
    (throw (IllegalArgumentException. "coll must have length 2.")))
  (if (odd? (first coll))
    (throw (IllegalArgumentException. "first elem must be even.")))
  (if (even? (second coll))
    (throw (IllegalArgumentException. "second elem must be odd.")))
  (apply * coll))

(defn f2 [coll]
  (if (not= (count coll) 2)
    (throw (IllegalArgumentException. "coll must have length 2.")))
  (if (odd? (first coll))
    (throw (IllegalArgumentException. "first elem must be even.")))
  (if (even? (second coll))
    (throw (IllegalArgumentException. "second elem must be odd.")))
  (apply + coll))


(defn f3 [coll]
  (if (not= (count coll) 2)
    (throw (IllegalArgumentException. "coll must have length 2.")))
  (if (odd? (first coll))
    (throw (IllegalArgumentException. "first elem must be even.")))
  (if (even? (second coll))
    (throw (IllegalArgumentException. "second elem must be odd.")))
  (apply / coll))

在这个简单的例子中,我可以分解出公共部分:

(defn qc [coll]
  (if (not= (count coll) 2)
    (throw (IllegalArgumentException. "coll must have length 2.")))
  (if (odd? (first coll))
    (throw (IllegalArgumentException. "first elem must be even.")))
  (if (even? (second coll))
    (throw (IllegalArgumentException. "second elem must be odd."))))

(defn f1 [coll]
  (qc coll)
  (apply + coll))

(defn f2 [coll]
  (qc coll)
  (apply - coll))

(defn f3 [coll]
  (qc coll)
  (apply / coll))

但在现实世界的应用程序中,这很快就会变得乏味。如果这些函数的 qc 步骤都略有不同怎么办?如果我想施加某些类型限制怎么办?

我想这是动态类型的缺点之一,但也许有一种方法可以使 clojure 中的事情变得更简单?

函数形式已内置pre and post conditions:

user> (defn f1 [coll]
        {:pre  [(= (count coll) 2)
                (odd? (first coll))
                (even? (second coll))]}
        (apply * coll))
#'user/f1
user> (f1 [1])
AssertionError Assert failed: (= (count coll) 2)  user/f1 (form-init2783181480380820413.clj:1)
user> (f1 [2 2])
AssertionError Assert failed: (odd? (first coll))  user/f1 (form-init2783181480380820413.clj:1)
user> (f1 [1 2])
2

虽然它会打印失败的表达式,但这些不会打印好的消息,因此您可以将其写得足够清楚以传达消息。