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


Я пришел с этой:

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

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

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

5 106

5 ответов:

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

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

вы также можете уничтожить 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)))

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

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

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

(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