Clojure:简洁地转发可选值

时间:2018-10-31 17:30:51

标签: clojure optional-parameters optional-arguments

我已经在Clojure中编写了一个概率函数,该函数具有可选的选项哈希表:

(defn roll-lte
  ([n d] (/ n d))
  ([n d options]
    (let [p (/ n d)
          roll-type (:type options :normal)]
      (cond
        (= roll-type :advantage) (- (* p 2) (* p p))
        (= roll-type :disadvantage) (* p p)
        (= roll-type :normal) p
        :else (throw (IllegalArgumentException. "Invalid roll type."))))))

这可以按预期工作,但是我们的想法是编写以此为基础的其他功能-例如:

(defn roll-gte
  ([n d] (roll-lte (- d n -1) d))
  ([n d options] (roll-lte (- d n -1) d options)))

roll-lte中的两个区域使该函数的构建变得笨拙且重复,尤其是在像上述那样的情况下,options仅被转发到roll-lte。有没有更简洁,更重复的方法来实现这一目标?

1 个答案:

答案 0 :(得分:3)

当我具有带有多个Arity的函数时,我通常会尝试使用安全的默认参数来使低arity版本调用高arity版本。该函数的“主要”实现通常最终会成为最高匹配的主体:

(defn roll-lte
  ([n d] (roll-lte n d nil))
  ([n d {:keys [type]
         :or   {type :normal}}]
   (let [p (/ n d)]
     (case type ;; used case instead of cond here
       :advantage (- (* p 2) (* p p))
       :disadvantage (* p p)
       :normal p
       (throw (IllegalArgumentException. "Invalid roll type."))))))

我还在上面的选项映射解构中使用了:or来设置type的默认值,这允许低等值函数仅传递nil个选项映射。

(defn roll-gte
  ([n d] (roll-gte n d nil))
  ([n d options] (roll-lte (- d n -1) d options)))

(roll-gte 3 4) ;=> 1/2
(roll-gte 3 4 {:type :advantage}) ;=> 3/4