Как создать значение по умолчанию для аргумента функции в Clojure - PullRequest
116 голосов
/ 09 июля 2010

Я прихожу с этим:

(defn string->integer [str & [base]]
  (Integer/parseInt str (if (nil? base) 10 base)))

(string->integer "10")
(string->integer "FF" 16)

Но это должен быть лучший способ сделать это.

Ответы [ 5 ]

156 голосов
/ 09 июля 2010

Функция может иметь несколько подписей, если подписи отличаются по арности.Вы можете использовать это для предоставления значений по умолчанию.

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

148 голосов
/ 29 декабря 2011

Вы также можете деструктурировать 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 (например)

32 голосов
/ 01 октября 2013

Это решение ближе к духу оригинального решения , но незначительно чище

(defn string->integer [str & [base]]
  (Integer/parseInt str (or base 10)))

A аналогичный шаблон , который может быть удобно использовать 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)))
8 голосов
/ 19 июля 2014

Существует другой подход, который вы можете рассмотреть: частичные функции. Возможно, это более «функциональный» и более гибкий способ задания значений по умолчанию для функций.

Начните с создания (при необходимости) функции, в которой есть параметры, которые вы хотите указать по умолчанию в качестве ведущего (ых) параметра (ов):

(defn string->integer [base str]
  (Integer/parseInt str base))

Это сделано потому, что версия Clojure partial позволяет указывать значения по умолчанию только в том порядке, в котором они указаны в определении функции. После того, как параметры упорядочены по желанию, вы можете создать версию функции по умолчанию, используя функцию partial:

(partial string->integer 10)

Чтобы сделать эту функцию вызываемой несколько раз, вы можете поместить ее в переменную, используя 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))

(обратите внимание, что это немного отличается от ответа Брайана, поскольку порядок параметров был изменен по причинам, указанным в верхней части этого ответа)

5 голосов
/ 21 сентября 2015

Вы также можете посмотреть на (fnil) https://clojuredocs.org/clojure.core/fnil

...