Clojure: кратко пересылайте необязательные значения - PullRequest
0 голосов
/ 31 октября 2018

Я написал функцию вероятности в 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 голосов
/ 31 октября 2018

Когда у меня есть функции с несколькими арностями, я обычно стараюсь, чтобы версии с более низкой артией вызывали версии с более высокой арностью с безопасными аргументами по умолчанию. «Основная» реализация функции обычно оказывается телом с наибольшей арностью:

(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
...