Відповіді:
Функція може мати декілька підписів, якщо підписи відрізняються за сутністю. Ви можете використовувати це для введення значень за замовчуванням.
(defn string->integer
([s] (string->integer s 10))
([s base] (Integer/parseInt s base)))
Зауважимо, що припущення falseта nilобидва вони вважаються нецінністю, їх (if (nil? base) 10 base)можна скоротити (if base base 10)або продовжити (or base 10).
recurпрацює лише на одній аристократиці. якщо ви спробували повторити вище, наприклад:java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2, compiling:
(string->integer s 10))?
Ви також можете деструктурувати restаргументи як карту з Clojure 1.2 [ ref ]. Це дозволяє називати та надавати за замовчуванням аргументи функції:
(defn string->integer [s & {:keys [base] :or {base 10}}]
(Integer/parseInt s base))
Тепер ви можете зателефонувати
(string->integer "11")
=> 11
або
(string->integer "11" :base 8)
=> 9
Ви можете побачити це в дії тут: https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (наприклад)
Це рішення ближче до духу оригінального рішення , але незначно чистіше
(defn string->integer [str & [base]]
(Integer/parseInt str (or base 10)))
Аналогічна картина , яка може бути зручно використання в orпоєднанні зlet
(defn string->integer [str & [base]]
(let [base (or base 10)]
(Integer/parseInt str base)))
Хоча в цьому випадку більш багатослівний, він може бути корисним, якщо ви хочете мати значення за замовчуванням залежні від інших вхідних значень . Наприклад, розглянемо таку функцію:
(defn exemplar [a & [b c]]
(let [b (or b 5)
c (or c (* 7 b))]
;; or whatever yer actual code might be...
(println a b c)))
(exemplar 3) => 3 5 35
Цей підхід легко розширити і для роботи з названими аргументами (як у рішенні М. Гілліара):
(defn exemplar [a & {:keys [b c]}]
(let [b (or b 5)
c (or c (* 7 b))]
(println a b c)))
Або використовуючи ще більше синтезу:
(defn exemplar [a & {:keys [b c] :or {b 5}}]
(let [c (or c (* 7 b))]
(println a b c)))
or
orвідрізняється від :orтого, orщо не знає різниці nilі false.
Ви можете скористатися ще одним підходом: часткові функції. Це, мабуть, більш "функціональний" і гнучкіший спосіб визначення значень за замовчуванням для функцій.
Почніть зі створення (за необхідності) функції, яка має параметри (параметри), які ви хочете надати за замовчуванням, як провідні параметри:
(defn string->integer [base str]
(Integer/parseInt str base))
Це робиться тому, що версія Clojure partialдозволяє надати значення "за замовчуванням" лише в тому порядку, який вони відображаються у визначенні функції. Після того, як параметри будуть упорядковані за бажанням, ви можете створити "типову" версію функції за допомогою partialфункції:
(partial string->integer 10)
Щоб цю функцію можна було викликати кілька разів, ви можете поставити її у var, використовуючи def:
(def decimal (partial string->integer 10))
(decimal "10")
;10
Ви також можете створити "локальний стандарт" за допомогою let:
(let [hex (partial string->integer 16)]
(* (hex "FF") (hex "AA")))
;43350
Підхід до часткової функції має одну ключову перевагу перед іншими: споживач функції все ще може вирішити, яким буде значення за замовчуванням, а не виробник функції, не потребуючи модифікації визначення функції . Це проілюстровано в прикладі, hexколи я вирішив, що функція за замовчуванням decimal- це не те, що я хочу.
Ще одна перевага цього підходу полягає в тому, що ви можете призначити функції за замовчуванням інше ім’я (десятковий, шістнадцятковий тощо), яке може бути більш описовим та / або іншою сферою застосування (var, local). При бажанні часткову функцію можна також змішати з деякими підходами, описаними вище:
(defn string->integer
([s] (string->integer s 10))
([base s] (Integer/parseInt s base)))
(def hex (partial string->integer 16))
(Зауважте, це дещо відрізняється від відповіді Брайана, оскільки порядок параметрів змінено з причин, наведених у верхній частині цієї відповіді)
Ви також можете заглянути на (fnil) https://clojuredocs.org/clojure.core/fnil
(recur s 10), використовуючиrecurзамість повторення назви функціїstring->integer. Це полегшить перейменування функції в майбутньому. Хтось знає якусь причину не використовуватиrecurв цих ситуаціях?